📄 mtp.c
字号:
struct mtp_event *event = (struct mtp_event *)ebuf;
event->typ = MTP_EVENT_DUMP;
event->dump.out = out;
gettimeofday(&event->dump.stamp, NULL);
event->dump.slinkno = m->slinkno;
if(sizeof(struct mtp_event) + len > MTP_MAX_PCK_SIZE) {
len = MTP_MAX_PCK_SIZE - sizeof(struct mtp_event);
}
event->len = len;
memcpy(event->buf, buf, len);
mtp_put(m, event);
}
#ifdef DO_RAW_DUMPS
static void mtp2_dump_raw(mtp2_t *m, unsigned char *buf, int len, int out) {
unsigned char ebuf[MTP_EVENT_MAX_SIZE];
struct mtp_event *event = (struct mtp_event *)ebuf;
event->typ = MTP_EVENT_RAWDUMP;
event->rawdump.out = out;
if(sizeof(struct mtp_event) + len > MTP_MAX_PCK_SIZE) {
len = MTP_MAX_PCK_SIZE - sizeof(struct mtp_event);
}
event->len = len;
memcpy(event->buf, buf, len);
mtp_put(m, event);
}
#endif
static int t17_timeout(void *data) {
mtp2_t *m = data;
fifo_log(m, LOG_DEBUG, "link %s\n", m->name);
m->mtp3_t17 = -1;
start_initial_alignment(m, "t17_timeout");
return 0; /* Do not re-schedule */
}
static void t17_stop(mtp2_t *m) {
if(m->mtp3_t17 != -1) {
mtp_sched_del(mtp2_sched, m->mtp3_t17);
m->mtp3_t17 = -1;
}
}
static void t17_start(mtp2_t *m) {
t17_stop(m);
m->mtp3_t17 = mtp_sched_add(mtp2_sched, 1200, t17_timeout, m);
}
static int t1_timeout(void *data) {
mtp2_t *m = data;
fifo_log(m, LOG_WARNING, "MTP2 timer T1 timeout (peer failed to complete "
"initial alignment), initial alignment failed on link '%s'.\n", m->name);
m->mtp2_t1 = -1;
abort_initial_alignment(m);
return 0; /* Do not re-schedule */
}
static void t1_stop(mtp2_t *m) {
if(m->mtp2_t1 != -1) {
mtp_sched_del(mtp2_sched, m->mtp2_t1);
m->mtp2_t1 = -1;
}
}
static void t1_start(mtp2_t *m) {
t1_stop(m);
m->mtp2_t1 = mtp_sched_add(mtp2_sched, 45000, t1_timeout, m);
}
static int t2_timeout(void *data) {
mtp2_t *m = data;
fifo_log(m, LOG_WARNING, "MTP2 timer T2 timeout (failed to receive 'O', 'N', "
"or 'E' after sending 'O'), initial alignment failed on link '%s'.\n", m->name);
m->mtp2_t2 = -1;
abort_initial_alignment(m);
return 0; /* Do not re-schedule */
}
static void t2_stop(mtp2_t *m) {
if(m->mtp2_t2 != -1) {
mtp_sched_del(mtp2_sched, m->mtp2_t2);
m->mtp2_t2 = -1;
}
}
static void t2_start(mtp2_t *m) {
t2_stop(m);
m->mtp2_t2 = mtp_sched_add(mtp2_sched, 75000, t2_timeout, m);
}
static int t3_timeout(void *data) {
mtp2_t *m = data;
fifo_log(m, LOG_WARNING, "MTP2 timer T3 timeout (failed to receive 'N', "
"or 'E' after sending 'O'), initial alignment failed on link '%s'.\n", m->name);
m->mtp2_t3 = -1;
abort_initial_alignment(m);
return 0; /* Do not re-schedule */
}
static void t3_stop(mtp2_t *m) {
if(m->mtp2_t3 != -1) {
mtp_sched_del(mtp2_sched, m->mtp2_t3);
m->mtp2_t3 = -1;
}
}
static void t3_start(mtp2_t *m) {
t3_stop(m);
m->mtp2_t3 = mtp_sched_add(mtp2_sched, 1500, t3_timeout, m);
}
static int t4_timeout(void *data) {
mtp2_t *m = data;
fifo_log(m, LOG_DEBUG, "Proving successful on link '%s'.\n", m->name);
m->state = MTP2_READY;
m->mtp2_t4 = -1;
t1_start(m);
return 0; /* Do not re-schedule */
}
static void t4_stop(mtp2_t *m) {
if(m->mtp2_t4 != -1) {
mtp_sched_del(mtp2_sched, m->mtp2_t4);
m->mtp2_t4 = -1;
}
}
static void t4_start(mtp2_t *m) {
t4_stop(m);
m->mtp2_t4 = mtp_sched_add(mtp2_sched, 500, t4_timeout, m);
}
static struct mtp2_state* get_inservice_schannel(struct link* link)
{
int i;
for (i = 0; i < this_host->n_schannels; i++) {
struct mtp2_state* m = &mtp2_state[i];
if (m->state == MTP2_INSERVICE) {
struct link* slink = m->link;
if (link->linkset == slink->linkset ||
is_combined_linkset(link->linkset, slink->linkset))
return m;
}
}
return NULL;
}
int mtp_has_inservice_schannels(struct link* link)
{
return (get_inservice_schannel(link) != NULL);
}
static mtp2_t* find_alternative_slink(mtp2_t* m)
{
struct mtp2_state* newm = NULL;
struct mtp2_state* alt_newm = NULL;
int i;
for (i = 0; i < this_host->n_schannels; i++) {
if (&mtp2_state[i] == m)
continue;
if (mtp2_state[i].state != MTP2_INSERVICE)
continue;
if (m->link->linkset == mtp2_state[i].link->linkset) {
newm = &mtp2_state[i];
break;
}
if (is_combined_linkset(m->link->linkset, mtp2_state[i].link->linkset))
alt_newm = &mtp2_state[i];
}
if (!newm)
newm = alt_newm;
return newm;
}
/* Flush MTP transmit buffer to other link or host */
static void mtp_changeover(mtp2_t *m) {
struct mtp2_state* newm = NULL;
int i;
int do_forward = 1;
for (i = 0; i < this_host->n_schannels; i++) {
struct mtp2_state* newm = &mtp2_state[i];
if (&mtp2_state[i] == m)
continue;
if (m->link->linkset != newm->link->linkset)
continue;
if (mtp2_state[i].state == MTP2_INSERVICE) {
newm = &mtp2_state[i];
break;
}
}
if (!newm) {
fifo_log(m, LOG_NOTICE, "MTP changeover last_ack=%d, last_sent=%d, from schannel %d, no INSERVICE schannel found\n", m->retrans_last_acked, m->retrans_last_sent, m->schannel);
if (this_host->has_signalling_receivers)
fifo_log(m, LOG_NOTICE, "Failover, using another host for signalling.\n");
if (!cluster_receivers_alive(m->link->linkset)) {
fifo_log(m, LOG_NOTICE, "Failover not possible, no other signalling link and no other host available.\n");
#if 1
/* Remove all MSU's - the user parts must deal with lost PDU's */
m->retrans_last_acked = MTP_NEXT_SEQ(m->retrans_last_sent);
m->retrans_seq = -1;
#endif
return;
}
}
fifo_log(m, LOG_NOTICE, "MTP changeover last_ack=%d, last_sent=%d, from schannel %d, to schannel %d\n", m->retrans_last_acked, m->retrans_last_sent, m->schannel, newm ? newm->schannel : -1);
i = MTP_NEXT_SEQ(m->retrans_last_acked);
while (i != MTP_NEXT_SEQ(m->retrans_last_sent)) {
int sio = m->retrans_buf[i].buf[3];
int len = m->retrans_buf[i].len-4;
unsigned char* buf = &m->retrans_buf[i].buf[4];
fifo_log(m, LOG_DEBUG, "MTP changeover seqno=%d, sio=%d, len=%d, is_moved=%d\n", i, sio, len, (sio & 0xf) > 3);
if (do_forward && ((sio & 0xf) >= 3)) { /* User and application parts */
if (newm) {
mtp2_queue_msu(newm, sio, buf, len);
}
else {
if ((sio & 0xf) == 0x5 /* ISUP */) {
unsigned char reqbuf[MTP_REQ_MAX_SIZE];
struct mtp_req *req = (struct mtp_req*) &reqbuf;
memcpy(req->buf, buf, len);
req->len = len;
req->typ = MTP_REQ_ISUP;
cluster_mtp_forward(req);
}
}
m->retrans_buf[i].buf[3] = 0;
m->retrans_buf[i].len = 5; /* Is now a LSSU */
m->retrans_buf[i].buf[3] = 2;
i = MTP_NEXT_SEQ(i);
}
}
}
/* Called on link errors that occur during initial alignment (before the link
is in service), and which should cause initial alignment to be aborted. The
initial alignment to be re-tried after a short delay (MTP3 T17). */
static void abort_initial_alignment(mtp2_t *m)
{
mtp2_cleanup(m);
m->state = MTP2_DOWN;
/* Retry the initial alignment after a small delay. */
t17_start(m);
fifo_log(m, LOG_DEBUG, "Aborted initial alignment on link '%s'.\n", m->name);
}
/* Called on link errors that occur after the link is brought into service and
which must cause the link to be brought out of service. This entails
notifying user-parts of the failure and initiating MTP3 link failover, when
that is implemented. */
static void mtp3_link_fail(mtp2_t *m, int down) {
struct mtp_event link_up_event;
int old_state = m->state;
mtp2_cleanup(m);
/* Notify user-parts. */
if(old_state == MTP2_INSERVICE) {
link_up_event.typ = MTP_EVENT_STATUS;
link_up_event.status.link_state = MTP_EVENT_STATUS_LINK_DOWN;
link_up_event.status.link = m->link;
link_up_event.len = 0;
mtp_put(m, &link_up_event);
mtp_changeover(m);
}
/* For now, restart initial alignment after a small delay. */
if (down) {
m->state = MTP2_DOWN;
t17_start(m);
}
else
m->state = MTP2_NOT_ALIGNED;
l4down(m);
fifo_log(m, LOG_DEBUG, "Fail on link '%s'.\n", m->name);
}
static void start_initial_alignment(mtp2_t *m, char* reason) {
m->state = MTP2_NOT_ALIGNED;
m->send_fib = 1;
m->send_bsn = 0x7f;
m->send_bib = 1;
m->tx_len = 0;
m->tx_sofar = 0;
m->retrans_seq = -1;
m->retrans_last_acked = 0x7f;
m->retrans_last_sent = 0x7f;
m->error_rate_mon = 0;
m->emon_dcount = 0;
m->emon_ncount = 0;
m->bsn_errors = 0;
fifo_log(m, LOG_DEBUG, "Starting initial alignment on link '%s', reason: %s.\n", m->name, reason);
t2_start(m);
}
static void t7_stop(mtp2_t *m) {
if(m->mtp2_t7 != -1) {
mtp_sched_del(mtp2_sched, m->mtp2_t7);
m->mtp2_t7 = -1;
}
}
static void mtp2_cleanup(mtp2_t *m) {
/* Stop SLTA response timeout. */
if(m->sltm_t1 != -1) {
mtp_sched_del(mtp2_sched, m->sltm_t1);
m->sltm_t1 = -1;
}
/* Stop sending SLTM. */
if(m->sltm_t2 != -1) {
mtp_sched_del(mtp2_sched, m->sltm_t2);
m->sltm_t2 = -1;
}
t1_stop(m);
t2_stop(m);
t3_stop(m);
t4_stop(m);
t7_stop(m);
t17_stop(m);
}
static void deliver_l4(mtp2_t *m, unsigned char *sif, int len, int sio) {
unsigned char ebuf[MTP_EVENT_MAX_SIZE];
struct mtp_event *event = (struct mtp_event *)ebuf;
if (sio == MTP_EVENT_ISUP) {
event->isup.link = NULL;
event->isup.slink = m->link;
event->isup.slinkix = m->link->linkix;
}
else{
event->sccp.slink = m->link;
event->sccp.slinkix = m->link->linkix;
}
event->typ = sio;
event->len = len;
memcpy(event->buf, sif, len);
mtp_put(m, event);
}
static int timeout_t7(void *data) {
mtp2_t *m = data;
m->mtp2_t7 = -1;
fifo_log(m, LOG_WARNING, "T7 timeout (excessive delay of acknowledgement) on link '%s', state=%d.\n", m->name, m->state);
mtp3_link_fail(m, 1);
return 0; /* Do not schedule us again. */
}
static void mtp2_t7_start(mtp2_t *m) {
t7_stop(m);
m->mtp2_t7 = mtp_sched_add(mtp2_sched, 1500, timeout_t7, m);
}
/* Signal unit error rate monitor (Q.703 (10.2)) */
static void mtp2_error_mon_count_frame(mtp2_t *m) {
if(m->state == MTP2_READY || m->state == MTP2_INSERVICE) {
m->emon_dcount = (m->emon_dcount + 1) % 256;
if(m->emon_dcount == 0 && m->error_rate_mon > 0) {
(m->error_rate_mon)--;
}
}
}
static void mtp2_octet_counting(mtp2_t *m) {
m->emon_ncount = 0;
}
static void mtp2_emon_count_error(mtp2_t *m) {
if(m->state == MTP2_READY || m->state == MTP2_INSERVICE) {
if(m->error_rate_mon < 64) {
(m->error_rate_mon)++;
if(m->error_rate_mon == 64) {
fifo_log(m, LOG_WARNING, "Excessive errors detected in signalling unit "
"error rate monitor, link failed on link '%s'.\n", m->name);
mtp3_link_fail(m, 0);
}
}
} else if(m->state == MTP2_PROVING) {
(m->error_rate_mon)++;
/* ToDo: For now we are always in emergency, but for non
emergency, proving is not aborted until error_rate_mon reaches
the value of 4 (Q.703 (10.3.4)). */
if(m->error_rate_mon >= 1) {
fifo_log(m, LOG_WARNING, "Excessive errors detected in alignment "
"error rate monitor, link failed on link '%s'.\n", m->name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -