OpenSS7
SS7 for the
Common Man

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified:

Home Overview Status News Documentation Resources About
   
 Overview
 Status
 News
 Documentation
 Resources
 About

   
Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/daemons/isupmon/isupcol.cpp


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(&timestamp, 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;
}


Home Index Prev Next More Download Info FAQ Mail   Home -> Resources -> Browse Source -> strss7/daemons/isupmon/isupcol.cpp

OpenSS7
SS7 for the
Common Man
Home Overview Status News Documentation Resources About

© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved.
Last modified: