OpenSS7 SS7 for the Common Man |
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
||||||||||||||||||||||||||
Home | Overview | Status | News | Documentation | Resources | About | |||||||||||||||||||||
File /code/strss7/daemons/isupmon/isupcol.cpp#ident "@(#) $Id: isupcol.cpp,v 0.8 2003/07/24 20:38:38 brian Exp $" static char const ident[] = "$Id: isupcol.cpp,v 0.8 2003/07/24 20:38:38 brian Exp $"; extern "C" { # include <unistd.h> # include <sys/types.h> # include <sys/stat.h> # include <fcntl.h> # include <sys/ioctl.h> # include <sys/poll.h> # include <errno.h> # include <string.h> # include <stdio.h> # include <signal.h> # include <sys/time.h> # include <sys/stropts.h> # include <ss7/lmi.h> # include <ss7/lmi_ioctl.h> # include <ss7/sdti.h> # include <ss7/sdti_ioctl.h> }; #include <iostream> #pragma implementation #include "isupcol.hh" #define complain(__error) \ do { \ Error e(__PRETTY_FUNCTION__, __error); \ return; \ } while (0) #define throwerr(__error) \ do { \ throw Error(__PRETTY_FUNCTION__, __error); \ } while (0) // -------------------------------------------------------------------------- // // Error // // -------------------------------------------------------------------------- Error::Error() { } Error::Error(const char *function, int error) { const char *errstr; // print to stderr or syslog on construction // don't need these attributes then if (error < 0) { errstr = strerror(-error); } else { switch (error) { case LMI_UNSPEC: errstr = "Unknown or unspecified"; break; case LMI_BADADDRESS: errstr = "Address was invalid"; break; case LMI_BADADDRTYPE: errstr = "Invalid address type"; break; case LMI_BADDIAL: errstr = "(not used)"; break; case LMI_BADDIALTYPE: errstr = "(not used)"; break; case LMI_BADDISPOSAL: errstr = "Invalid disposal parameter"; break; case LMI_BADFRAME: errstr = "Defective SDU received"; break; case LMI_BADPPA: errstr = "Invalid PPA identifier"; break; case LMI_BADPRIM: errstr = "Unregognized primitive"; break; case LMI_DISC: errstr = "Disconnected"; break; case LMI_EVENT: errstr = "Protocol-specific event ocurred"; break; case LMI_FATALERR: errstr = "Device has become unusable"; break; case LMI_INITFAILED: errstr = "Link initialization failed"; break; case LMI_NOTSUPP: errstr = "Primitive not supported by this device"; break; case LMI_OUTSTATE: errstr = "Primitive was issued from invalid state"; break; case LMI_PROTOSHORT: errstr = "M_PROTO block too short"; break; case LMI_SYSERR: errstr = "UNIX system error"; break; case LMI_WRITEFAIL: errstr = "Unitdata request failed"; break; case LMI_CRCERR: errstr = "CRC or FCS error"; break; case LMI_DLE_EOT: errstr = "DLE EOT detected"; break; case LMI_FORMAT: errstr = "Format error detected"; break; case LMI_HDLC_ABORT: errstr = "Aborted frame detected"; break; case LMI_OVERRUN: errstr = "Input overrun"; break; case LMI_TOOSHORT: errstr = "Frame too short"; break; case LMI_INCOMPLETE: errstr = "Partial frame received"; break; case LMI_BUSY: errstr = "Telephone was busy"; break; case LMI_NOANSWER: errstr = "Connection went unanswered"; break; case LMI_CALLREJECT: errstr = "Connection rejected"; break; case LMI_HDLC_IDLE: errstr = "HDLC line went idle"; break; case LMI_HDLC_NOTIDLE: errstr = "HDLC link no longer idle"; break; case LMI_QUIESCENT: errstr = "Line being reassigned"; break; case LMI_RESUMED: errstr = "Line has been reassigned"; break; case LMI_DSRTIMEOUT: errstr = "Did not see DSR in time"; break; case LMI_LAN_COLLISIONS: errstr = "LAN excessive collisions"; break; case LMI_LAN_REFUSED: errstr = "LAN message refused"; break; case LMI_LAN_NOSTATION: errstr = "LAN no such station"; break; case LMI_LOSTCTS: errstr = "Lost Clear to Send signal"; break; case LMI_DEVERR: errstr = "Start of device-specific error codes"; break; default: errstr = "(unknown)"; break; } } cerr.form("%s: %s\n", function, errstr); } // -------------------------------------------------------------------------- // // Pollable // // -------------------------------------------------------------------------- int Pollable::npfd = 0; struct pollfd Pollable::pfd[] = { {0, 0, 0}, }; Pollable *Pollable::list = NULL; void Pollable::poll_recalc(Pollable * p) { if (p) { int fd = p->pfdp->fd; int events = p->pfdp->events; int revents = p->pfd->revents; poll_recalc(p->next); p->pfdp = &pfd[npfd++]; p->pfdp->fd = fd; p->pfdp->events = events; p->pfdp->revents = revents; } else { npfd = 0; } } Pollable::Pollable(const char *fname) { int fd; pfdp = NULL; if (npfd >= MAXPOLL) throwerr(-ENFILE); fd = this->poll_open(fname); // throws Error on failure // add ourselves to end of list pfdp = &pfd[npfd++]; pfdp->fd = fd; pfdp->events = POLLIN | POLLPRI; pfdp->revents = 0; // put ourselves on the master list if ((next = list)) next->prev = &next; list = this; prev = &list; } Pollable::~Pollable() { // remove from master list if ((*prev = next)) next->prev = prev; next = NULL; prev = &next; if (pfdp) { // close fd this->poll_close(pfdp->fd); pfdp->fd = 0; pfdp->events = 0; pfdp->revents = 0; // collapse poll fd list poll_recalc(list); } } void Pollable::poll_loop(int wait) { int ret, i; // run the poll on all pollables while (npfd) { if ((ret = poll(pfd, npfd, wait)) >= 0) { for (i = 0; i < npfd && ret > 0; i++) { if (pfd[i].revents & pfd[i].events) { this->poll_event(); // process event ret--; } } } else { // should at least display error } } } // -------------------------------------------------------------------------- // // Buffer // // -------------------------------------------------------------------------- StreamBuffer::StreamBuffer(SignallingTerminal & st) : sigTerm(st) { ctrl.buf = (char *) cbuf; ctrl.maxlen = BUFSIZE; ctrl.len = 0; data.buf = (char *) dbuf; data.maxlen = BUFSIZE; data.len = 0; } StreamBuffer::~StreamBuffer() { } RxStreamBuffer::RxStreamBuffer(SignallingTerminal & st) : StreamBuffer(st) { int type, ret, flags = 0; if ((ret = getmsg(st.pfdp->fd, &ctrl, &data, &flags)) < 0) throw Error(__PRETTY_FUNCTION__, -errno); if (ctrl.len > 0) { st.primitive(this); return; } if (data.len > 0) { st.message(this); return; } throw Error(__PRETTY_FUNCTION__, -EPROTO); } RxStreamBuffer::~RxStreamBuffer() { } TxStreamBuffer::TxStreamBuffer(SignallingTerminal & st, ulong csize = 0, ulong dsize = 0) : StreamBuffer(st) { if (csize > BUFSIZE || dsize > BUFSIZE) throw Error(__PRETTY_FUNCTION__, -EFAULT); ctrl.len = csize; data.len = dsize; } TxStreamBuffer::~TxStreamBuffer() { } void TxStreamBuffer::send(int flags) { int ret; if ((ret = putmsg(sigTerm.pfdp->fd, ctrl.len ? &ctrl : NULL, data.len ? &data : NULL, flags)) < 0) throw Error(__PRETTY_FUNCTION__, -errno); } // -------------------------------------------------------------------------- // // SignallingTerminal // // -------------------------------------------------------------------------- SignallingTerminal::SignallingTerminal(const char *devname, ulong ppa, Network & n) :Pollable(devname), state(LMI_UNUSABLE), network(n) { TxStreamBuffer *b; int ret; union { union LMI_primitives l; union SDT_primitives s; } *p; // always place in master list if ((next = list)) next->prev = &next; list = this; prev = &list; if (!pfdp) goto efault; if (!pfdp->fd) goto ebadf; if (!(b = new TxStreamBuffer(*this, sizeof(*p), 0))) throw Error(__PRETTY_FUNCTION__, -ENOMEM); p = (typeof(p)) b->ctrl.buf; b->ctrl.len = sizeof(p->l.info_req); p->l.lmi_primitive = LMI_INFO_REQ; b->send(RS_HIPRI); state = LMI_UNUSABLE; poll_loop(-1); if (state == LMI_UNUSABLE) goto eproto; if (style == LMI_STYLE1) goto enable; b->ctrl.len = sizeof(p->l.attach_req) + sizeof(ulong); p->l.lmi_primitive = LMI_ATTACH_REQ; *(ulong *) p->l.attach_req.lmi_ppa = ppa; b->send(RS_HIPRI); state = LMI_ATTACH_PENDING; poll_loop(-1); if (state != LMI_DISABLED) goto eproto; enable: b->ctrl.len = sizeof(p->l.enable_req); p->l.lmi_primitive = LMI_ENABLE_REQ; b->send(RS_HIPRI); state = LMI_ENABLE_PENDING; poll_loop(-1); if (state != LMI_ENABLED) goto eproto; ctrl.len = sizeof(p->s.daedr_start_req); p->s.sdt_primitive = SDT_DAEDR_START_REQ; b->send(RS_HIPRI); return; efault: errno = EFAULT; goto error; ebadf: errno = EBADF; goto error; eproto: errno = EPROTO; goto error; error: throwerr(-errno); } SignallingTerminal::~SignallingTerminal() { TxStreamBuffer *b; int ret; union { union LMI_primitives l; union SDT_primitives s; } *p; // always remove from master list if ((*prev = next)) next->prev = prev; next = NULL; prev = &next; if (!pfdp) goto efault; if (!pfdp->fd) goto ebadf; if (!(b = new TxStreamBuffer(*this, sizeof(*p), 0))) throw Error(__PRETTY_FUNCTION__, -ENOMEM); p = (typeof(p)) b->ctrl.buf; switch (state) { case LMI_ENABLED: case LMI_ENABLE_PENDING: b->ctrl.len = sizeof(p->l.disable_req); p->l.lmi_primitive = LMI_DISABLE_REQ; b->send(RS_HIPRI); state = LMI_DISABLE_PENDING; poll_loop(-1); if (state != LMI_DISABLED) goto eproto; case LMI_DISABLE_PENDING: case LMI_DISABLED: case LMI_ATTACH_PENDING: if (style == LMI_STYLE1) goto detached; b->ctrl.len = sizeof(p->l.detach_req); p->l.lmi_primitive = LMI_DETACH_REQ; b->send(RS_HIPRI); state = LMI_DETACH_PENDING; poll_loop(-1); if (state != LMI_UNATTACHED) return; default: case LMI_DETACH_PENDING: case LMI_UNATTACHED: case LMI_UNUSABLE: detached: break; } return; efault: errno = EFAULT; goto error; ebadf: errno = EBADF; goto error; eproto: errno = EPROTO; goto error; error: complain(-errno); } int SignallingTerminal::poll_open(const char *name) { int fd, ret; if ((ret = open(name, O_NONBLOCK | O_RDWR)) < 0) goto error; fd = ret; if ((ret = ioctl(fd, I_SRDOPT, RMSGD)) < 0) goto error; if ((ret = ioctl(fd, I_SETCLTIME, 0)) < 0) goto error; state = LMI_UNATTACHED; return (fd); error: throwerr(-errno); } void SignallingTerminal::poll_close(int fd) { int ret; if ((ret = close(fd)) < 0) goto error; return; error: complain(-errno); return; } void SignallingTerminal::poll_event() { try { if (!(new RxStreamBuffer(*this))) throw Error(__PRETTY_FUNCTION__, -ENOMEM); return; } catch(Error e) { return; } } void SignallingTerminal::primitive(StreamBuffer * buf) { union LMI_primitives *l; l = (typeof(l)) buf->ctrl.buf; switch (l->lmi_primitive) { case SDT_RC_SIGNAL_UNIT_IND: message(buf); return; case SDT_RC_CONGESTION_ACCEPT_IND: case SDT_RC_CONGESTION_DISCARD_IND: case SDT_RC_NO_CONGESTION_IND: case SDT_IAC_CORRECT_SU_IND: case SDT_IAC_ABORT_PROVING_IND: case SDT_LSC_LINK_FAILURE_IND: case SDT_TXC_TRANSMISSION_REQUEST_IND: break; case LMI_INFO_ACK: state = l->info_ack.lmi_state; style = l->info_ack.lmi_ppa_style; max_sdu = l->info_ack.lmi_max_sdu; min_sdu = l->info_ack.lmi_min_sdu; hdr_len = l->info_ack.lmi_header_len; break; case LMI_OK_ACK: state = l->ok_ack.lmi_state; break; case LMI_ERROR_ACK: state = l->error_ack.lmi_state; if (l->error_ack.lmi_errno == LMI_SYSERR) complain(-l->error_ack.lmi_reason); else complain(l->error_ack.lmi_errno); break; case LMI_ENABLE_CON: state = l->enable_con.lmi_state; break; case LMI_DISABLE_CON: state = l->disable_con.lmi_state; break; case LMI_ERROR_IND: state = l->error_ack.lmi_state; // we should try to reinitialize the SDT if (l->error_ack.lmi_errno == LMI_SYSERR) complain(-l->error_ack.lmi_reason); else complain(l->error_ack.lmi_errno); break; case LMI_OPTMGMT_ACK: case LMI_STATS_IND: case LMI_EVENT_IND: default: // discard break; } delete buf; return; } void SignallingTerminal::message(StreamBuffer * buf) { if (buf->data.len < hdr_len) throw Error(__PRETTY_FUNCTION__, -EPROTO); buf->data.buf += hdr_len; // pull header buf->data.len -= hdr_len; if (!(new Message(*this, buf))) throw Error(__PRETTY_FUNCTION__, -ENOMEM); } void SignallingTerminal::buffer(StreamBuffer * buf) { if (buf->ctrl.len > 0) return primitive(buf); if (buf->data.len > 0) return message(buf); delete buf; return; } // -------------------------------------------------------------------------- // // Message // // -------------------------------------------------------------------------- Message::Message(SignallingTerminal & st, StreamBuffer * buf) : network(st.network), buffer(buf), index(st.index), p((unsigned char *) (buf->data.buf)), e((unsigned char *) (buf->data.buf + buf->data.len)) { ulong b; if (gettimeofday(×tamp, NULL) < 0) throw Error(__PRETTY_FUNCTION__, -errno); switch (network.pvar & SS7_PVAR_MASK) { case SS7_PVAR_ANSI: /* 24-bit point codes */ case SS7_PVAR_JTTC: case SS7_PVAR_CHIN: if (p + 11 >= e) throw Error(); si = mp = ni = *p++; si &= 0x0f; if (si != 0x05) throw Error(); ni >>= 4; ni &= 0x03; mp >>= 6; mp &= 0x03; b = *p++ & 0x00ff; dpc = b; b = *p++ & 0x00ff; dpc |= b << 8; b = *p++ & 0x00ff; dpc |= b << 16; b = *p++ & 0x00ff; opc = b; b = *p++ & 0x00ff; opc |= b << 8; b = *p++ & 0x00ff; opc |= b << 16; b = *p++ & 0x00ff; sls = b; b = *p++ & 0x00ff; cic = b; b = *p++ & 0x00ff; cic |= b << 8; b = *p++ & 0x00ff; mt = (typeof(mt))b; break; default: case SS7_PVAR_ITUT: /* 14-bit point codes */ case SS7_PVAR_ETSI: case SS7_PVAR_SING: case SS7_PVAR_SPAN: if (p + 8 >= e) throw Error(); si = ni = mp = *p++; si &= 0x0f; if (si != 0x05) throw Error(); ni >>= 4; ni &= 0x0f; mp = 0; b = *p++ & 0x00ff; dpc = b; b = *p++ & 0x00ff; dpc |= b << 8; dpc &= 0x3fff; opc = b >> 6; b = *p++ & 0x00ff; opc |= b << 2; b = *p++ & 0x00ff; opc |= b << 10; opc &= 0x3fff; sls = b >> 4; b = *p++ & 0x00ff; cic = b; b = *p++ & 0x00ff; cic |= b << 8; cic &= 0x0fff; b = *p++ & 0x00ff; mt = (typeof(mt))b; break; } network.message(this); } Message::~Message() { if ((*prev = next)) next->prev = prev; } // link message into list (with counts and duplicate checks) int Message::link(Message * list) { Message *m; // First we need to see whether we already have a message of the // specified message type in the message lists. If we do, then if the // new message is identical in all ISUP respects to the current message // and the timestamps are rather close, then the message is a duplicate // and can be discarded (we do update the timestamp to the lastest // timestamped message to handle retransmissions at MTP level). for (m = list; m; m = m->next) { if (m->mt != mt) continue; if (m->dpc != dpc) continue; // only when swapped if (m->opc != opc) continue; // only when swapped if (m->cic != cic) continue; // really a bad error if (m->mp != mp) continue; if (m->ni != ni) continue; if (m->sls != sls) continue; if (m->e - m->p != e - p) continue; // different length if (bcmp(m->p, p, e - p)) continue; // different contents // ok, here we have identical messages except for timestamps if // a significant time has elapsed since we received the first // message, then we might want to process the message anyway // return the number of seconds difference between the messages // note that this might be a negative value return (timestamp.tv_sec - m->timestamp.tv_sec); } // message is unique, add it to the list if ((next = list)) next->prev = &next; list = this; prev = &list; return (0); } // unlink message from list void Message::unlink() { if (prev != &next) { if ((*prev = next)) next->prev = prev; next = NULL; prev = &next; } } // dump messages void Message::dump() { int i; if (next) next->dump(); // network index cout.put((unsigned char) ((timestamp.tv_sec >> 24) & 0x00ff)); cout.put((unsigned char) ((timestamp.tv_sec >> 16) & 0x00ff)); cout.put((unsigned char) ((timestamp.tv_sec >> 8) & 0x00ff)); cout.put((unsigned char) ((timestamp.tv_sec >> 0) & 0x00ff)); cout.put((unsigned char) ((timestamp.tv_usec >> 24) & 0x00ff)); cout.put((unsigned char) ((timestamp.tv_usec >> 16) & 0x00ff)); cout.put((unsigned char) ((timestamp.tv_usec >> 8) & 0x00ff)); cout.put((unsigned char) ((timestamp.tv_usec >> 0) & 0x00ff)); cout.put((unsigned char) ((buffer->data.len >> 8) & 0x00ff)); cout.put((unsigned char) ((buffer->data.len >> 0) & 0x00ff)); for (i = 0; i < buffer->data.len; i++) cout.put(buffer->data.buf[i]); } // -------------------------------------------------------------------------- // // Network // // -------------------------------------------------------------------------- Network::Network(ulong i, ulong p):pvar(p), index(i) { } Network::~Network() { int i; for (i = 0; i < HASH_TABLE_SIZE; i++) while (hash[i]) delete hash[i]; } Call *&Network::hash_slot(ulong dpc, ulong opc, ulong cic) { ulong slot; slot = dpc + opc + cic; slot = ((slot >> 0) ^ (slot >> 8) ^ (slot >> 16) ^ (slot >> 24)) & (HASH_TABLE_SIZE - 1); return hash[slot]; } Call *Network::lookup(ulong dpc, ulong opc, ulong cic) { Call *c; if (!(c = hash_slot(dpc, opc, cic)) || !(c = c->lookup(dpc, opc, cic))) if (!(c = new Call(*this, dpc, opc, cic))) throw Error(__PRETTY_FUNCTION__, -errno); return (c); } void Network::message(Message * m) { Call *c; if (!(c = lookup(m->dpc, m->opc, m->cic))) throw Error(__PRETTY_FUNCTION__, -ENOMEM); c->message(m); } // -------------------------------------------------------------------------- // // Network // // -------------------------------------------------------------------------- // CTOR Call::Call(Network & n, ulong d, ulong o, ulong c):network(n), next(NULL), prev(&next), dpc(d), opc(o), cic(c), list(NULL), state(CTS_IDLE) { // link into hash table Call *&slot = n.hash_slot(d, o, c); if ((next = slot)) next->prev = &next; slot = this; prev = &slot; } // DTOR Call::~Call() { // delete all our messages while (list) delete list; // delete ourselves from the hash tables if ((*prev = next)) next->prev = prev; } Call *Call::lookup(ulong d, ulong o, ulong c) { if (this && (d != dpc || o != opc || c != cic)) return next->lookup(d, o, c); return (this); } void Call::clear() { state = CTS_IDLE; while (list) delete list; } // binary dump of call void Call::dump() { int cnt; Message *m; for (cnt = 0, m = list; m; cnt++, m = m->next) ; if (cnt && state > CTS_WAIT_ACM) { cout.put((unsigned char) (network.index & 0x00ff)); cout.put((unsigned char) ((dpc >> 16) & 0x00ff)); cout.put((unsigned char) ((dpc >> 8) & 0x00ff)); cout.put((unsigned char) ((dpc >> 0) & 0x00ff)); cout.put((unsigned char) ((opc >> 16) & 0x00ff)); cout.put((unsigned char) ((opc >> 8) & 0x00ff)); cout.put((unsigned char) ((opc >> 0) & 0x00ff)); cout.put((unsigned char) ((cic >> 8) & 0x00ff)); cout.put((unsigned char) ((cic >> 0) & 0x00ff)); cout.put((unsigned char) (cnt & 0x00ff)); if (list) list->dump(); } clear(); } // // process message for call - this is the main correlation state machine // function for correlating ISUP messages that belong to the same circuit // identification code - any correlation bugs will be found here // void Call::message(Message * m) { int delta; const bool ansi = ((network.pvar & SS7_PVAR_MASK) == SS7_PVAR_ANSI); if ((delta = m->link(list)) != 0) { // if the time delta between duplicate messages is significant, // and depending on the message type, we either discard the // message or reset the call state - for now we will just // discard duplicates delete m; return; } // process call state switch (m->mt) { case Message::ISUP_MT_IAM: // 0x01 - 0b00000001 - Initial address switch (state) { case CTS_IDLE: case CTS_WAIT_ACM: // glare scenario, one will back down break; default: // should not happen, cut partial and restart m->unlink(); dump(); m->link(list); break; } state = CTS_WAIT_ACM; break; case Message::ISUP_MT_SAM: // 0x02 - 0b00000010 - Subsequent address (not ANSI) if (ansi) goto discard; break; case Message::ISUP_MT_INR: // 0x03 - 0b00000011 - Information request case Message::ISUP_MT_INF: // 0x04 - 0b00000100 - Information case Message::ISUP_MT_COT: // 0x05 - 0b00000101 - Continuity break; case Message::ISUP_MT_ACM: // 0x06 - 0b00000110 - Address complete if (state != CTS_WAIT_ACM) goto discard; state = CTS_WAIT_ANM; break; case Message::ISUP_MT_CON: // 0x07 - 0b00000111 - Connect (not ANSI) if (ansi) goto discard; if (state != CTS_WAIT_ANM) goto discard; state = CTS_ANSWERED; break; case Message::ISUP_MT_FOT: // 0x08 - 0b00001000 - Forward transfer break; case Message::ISUP_MT_ANM: // 0x09 - 0b00001001 - Answer if (state != CTS_WAIT_ANM) goto discard; state = CTS_ANSWERED; break; case Message::ISUP_MT_REL: // 0x0c - 0b00001100 - Release break; case Message::ISUP_MT_SUS: // 0x0d - 0b00001101 - Suspend if (state != CTS_ANSWERED && state != CTS_SUSPENDED) goto discard; state = CTS_SUSPENDED; break; case Message::ISUP_MT_RES: // 0x0e - 0b00001110 - Resume if (state != CTS_ANSWERED && state != CTS_SUSPENDED) goto discard; state = CTS_ANSWERED; break; case Message::ISUP_MT_RLC: // 0x10 - 0b00010000 - Release complete case Message::ISUP_MT_CCR: // 0x11 - 0b00010001 - Continuity check request dump(); break; case Message::ISUP_MT_RSC: // 0x12 - 0b00010010 - Reset circuit if (state > CTS_WAIT_ANM) dump(); clear(); break; case Message::ISUP_MT_BLO: // 0x13 - 0b00010011 - Blocking if (state < CTS_WAIT_ANM) clear(); break; case Message::ISUP_MT_UBL: // 0x14 - 0b00010100 - Unblcoking break; case Message::ISUP_MT_BLA: // 0x15 - 0b00010101 - Blocking acknowledgement if (state < CTS_WAIT_ANM) clear(); break; case Message::ISUP_MT_UBA: // 0x16 - 0b00010110 - Unblocking acknowledgement break; case Message::ISUP_MT_GRS: // 0x17 - 0b00010111 - Circuit group reset // need to expand and find other calls if (state > CTS_WAIT_ANM) dump(); else clear(); clear(); break; case Message::ISUP_MT_CGB: // 0x18 - 0b00011000 - Circuit group blocking // need to expand and find other calls if (state < CTS_WAIT_ANM) clear(); break; case Message::ISUP_MT_CGU: // 0x19 - 0b00011001 - Circuit group unblocking break; case Message::ISUP_MT_CGBA: // 0x1a - 0b00011010 - Circuit group blocking acknowledgement // need to expand and find other calls if (state < CTS_WAIT_ANM) clear(); break; case Message::ISUP_MT_CGUA: // 0x1b - 0b00011011 - Circuit group unblocking acknowledgement break; case Message::ISUP_MT_CMR: // 0x1c - 0b00011100 - Call Modification Request (not ANSI) case Message::ISUP_MT_CMC: // 0x1d - 0b00011101 - Call Modification Completed (not ANSI) case Message::ISUP_MT_CMRJ: // 0x1e - 0b00011110 - Call Modification Reject (not ANSI) case Message::ISUP_MT_FAR: // 0x1f - 0b00011111 - Facility request (not ANSI) case Message::ISUP_MT_FAA: // 0x20 - 0b00100000 - Facility accepted (not ANSI) case Message::ISUP_MT_FRJ: // 0x21 - 0b00100001 - Facility reject (not ANSI) case Message::ISUP_MT_FAD: // 0x22 - 0b00100010 - Facility Deactivated (old Bellcore only) (not ANSI) case Message::ISUP_MT_FAI: // 0x23 - 0b00100011 - Facility Information (old Bellcore only) (not ANSI) if (ansi) goto discard; break; case Message::ISUP_MT_LPA: // 0x24 - 0b00100100 - Loop back acknowledgement break; case Message::ISUP_MT_CSVQ: // 0x25 - 0b00100101 - CUG Selection and Validation Request (not ANSI) case Message::ISUP_MT_CSVR: // 0x26 - 0b00100110 - CUG Selection and Validation Response (not ANSI) case Message::ISUP_MT_DRS: // 0x27 - 0b00100111 - Delayed release (not ANSI) if (ansi) goto discard; break; case Message::ISUP_MT_PAM: // 0x28 - 0b00101000 - Pass along break; case Message::ISUP_MT_GRA: // 0x29 - 0b00101001 - Circuit group reset acknowledgement // need to expand and find other calls if (state > CTS_WAIT_ANM) dump(); else clear(); clear(); break; case Message::ISUP_MT_CQM: // 0x2a - 0b00101010 - Circuit group query break; case Message::ISUP_MT_CQR: // 0x2b - 0b00101011 - Circuit group query response // need to expand and find other calls break; case Message::ISUP_MT_CPG: // 0x2c - 0b00101100 - Call progress if (state != CTS_WAIT_ACM && state != CTS_WAIT_ANM) goto discard; break; case Message::ISUP_MT_USR: // 0x2d - 0b00101101 - User-to-user information (not ANSI) if (ansi) goto discard; break; case Message::ISUP_MT_UCIC: // 0x2e - 0b00101110 - Unequipped circuit identification code clear(); break; case Message::ISUP_MT_CFN: // 0x2f - 0b00101111 - Confusion if (state < CTS_ANSWERED) clear(); break; case Message::ISUP_MT_OLM: // 0x30 - 0b00110000 - Overload (not ANSI) case Message::ISUP_MT_CRG: // 0x31 - 0b00110001 - Charge information (not ANSI) case Message::ISUP_MT_NRM: // 0x32 - 0b00110010 - Network resource management (not ANSI) if (ansi) goto discard; break; case Message::ISUP_MT_FAC: // 0x33 - 0b00110011 - Facility break; case Message::ISUP_MT_UPT: // 0x34 - 0b00110100 - User part test (not ANSI) case Message::ISUP_MT_UPA: // 0x35 - 0b00110101 - User part available (not ANSI) case Message::ISUP_MT_IDR: // 0x36 - 0b00110110 - Identification request (not ANSI) case Message::ISUP_MT_IRS: // 0x37 - 0b00110111 - Identification response (not ANSI) if (ansi) goto discard; break; case Message::ISUP_MT_SGM: // 0x38 - 0b00111000 - Segmentation break; case Message::ISUP_MT_CRA: // 0xe9 - 0b11101001 - Circuit Reservation Ack (ANSI 2000) if (state != CTS_WAIT_ACM) goto discard; state = CTS_WAIT_ANM; break; case Message::ISUP_MT_CRM: // 0xea - 0b11101010 - Circuit Reservation (ANSI 2000) switch (state) { case CTS_IDLE: case CTS_WAIT_ACM: // glare scenario, one will back down break; default: // should not happen, cut partial and restart m->unlink(); dump(); m->link(list); break; } state = CTS_WAIT_ACM; break; case Message::ISUP_MT_CVR: // 0xeb - 0b11101011 - Circuit Validation Response (ANSI 2000) case Message::ISUP_MT_CVT: // 0xec - 0b11101100 - Circuit Validation Test (ANSI 2000) break; case Message::ISUP_MT_EXM: // 0xed - 0b11101101 - Exit (old Bellcore/ANSI 2000) if (state != CTS_ANSWERED && state != CTS_SUSPENDED && state != CTS_WAIT_RLC) clear(); dump(); break; case Message::ISUP_MT_NON: // 0xf8 - 0b11111000 - National Notification (Spain) case Message::ISUP_MT_LLM: // 0xfc - 0b11111100 - National Malicious Call (Spain) case Message::ISUP_MT_CAK: // 0xfd - 0b11111101 - Charge Acknowledgement (Singapore) case Message::ISUP_MT_TCM: // 0xfe - 0b11111110 - Tariff Charge (Singapore) case Message::ISUP_MT_MCP: // 0xff - 0b11111111 - Malicious Call Print (Singapore) default: // unrecognized message break; } return; discard: // discard the message (removes it from list) delete m; return; }
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |