📄 mtp.c
字号:
return;
}
}
else if(m->state == MTP2_READY) {
t1_stop(m);
t7_stop(m);
}
/* ToDo: Check for FIB flipover when we haven't requested retransmission,
and fault the frame if so. See last part of Q.703 (5.3.2). */
/* Process the BSN of the received frame. */
if((m->retrans_last_acked <= m->retrans_last_sent &&
(bsn < m->retrans_last_acked || bsn > m->retrans_last_sent)) ||
(m->retrans_last_acked > m->retrans_last_sent &&
(bsn < m->retrans_last_acked && bsn > m->retrans_last_sent))) {
/* They asked for a retransmission of a sequence number not available. */
fifo_log(m, LOG_DEBUG, "Received illegal BSN=%d (retrans=%d,%d) on link '%s', len=%d, si=02%02x, state=%d, count=%d.\n",
bsn, m->retrans_last_acked, m->retrans_last_sent, m->name, len, m->tx_buffer[3] & 0xf, m->state, m->bsn_errors);
/* ToDo: Fault the link if this happens again within the next
two SUs, see second last paragraph of Q.703 (5.3.1). */
if (m->bsn_errors++ > 2) {
m->bsn_errors = 0;
mtp3_link_fail(m, 1);
}
return;
}
m->bsn_errors = 0;
/* Reset timer T7 if new acknowledgement received (Q.703 (5.3.1) last
paragraph). */
if(m->retrans_last_acked != bsn) {
t7_stop(m);
m->retrans_last_acked = bsn;
if(m->retrans_last_acked != m->retrans_last_sent) {
mtp2_t7_start(m);
}
}
if(bib != m->send_fib) {
/* Received negative acknowledge, start re-transmission. */
m->send_fib = bib;
if(bsn == m->retrans_last_sent) {
/* Nothing to re-transmit. */
m->retrans_seq = -1;
} else {
m->retrans_seq = MTP_NEXT_SEQ(bsn);
}
}
/* Process the signal unit content. */
if(li == 0) {
/* Fill-in signal unit. */
/* Process the FSN of the received frame. */
if(fsn != m->send_bsn) {
/* This indicates the loss of a message. */
if(fib == m->send_bib) {
/* Send a negative acknowledgement, to request retransmission. */
m->send_bib = !m->send_bib;
}
}
} else {
/* Message signal unit. */
/* Process the FSN of the received frame. */
if(fsn == m->send_bsn) {
/* Q.703 (5.2.2.c.i): Redundant retransmission. */
return;
} else if(fsn == MTP_NEXT_SEQ(m->send_bsn)) {
/* Q.703 (5.2.2.c.ii). */
if(fib == m->send_bib) {
/* Successful frame reception. Do explicit acknowledge on next frame. */
m->send_bsn = fsn;
} else {
/* Drop frame waiting for retransmissions to arrive. */
return;
}
} else {
/* Q.703 (5.2.2.c.iii). Frame lost before this frame, discart it
(will be retransmitted in-order later). */
if(fib == m->send_bib) {
/* Send a negative acknowledgement, to request retransmission. */
m->send_bib = !m->send_bib;
}
return;
}
/* Length indicator (li) is number of bytes in MSU after LI, so the valid
bytes are buf[0] through buf[(li + 3) - 1]. */
if(li < 5) {
fifo_log(m, LOG_NOTICE, "Got short MSU (no label), li=%d on link '%s'.\n", li, m->name);
return;
}
{
char pbuf[1000], hex[30];
int i;
strcpy(pbuf, "");
for(i = 0; i < li - 1 && i + 4 < len; i++) {
sprintf(hex, " %02x", buf[i + 4]);
strcat(pbuf, hex);
}
fifo_log(m, LOG_DEBUG, "Got MSU on link '%s' sio=%d slc=%d m.sls=%d bsn=%d/%d, fsn=%d/%d, sio=%02x, len=%d:%s\n", m->name, buf[3] & 0xf, (buf[7] & 0xf0) >> 4, m->sls, bib, bsn, fib, fsn, buf[3], li, pbuf);
}
process_msu(m, buf, len);
}
}
static void process_msu(struct mtp2_state* m, unsigned char* buf, int len)
{
mtp2_t* tm;
int service_indicator, subservice_field;
int h0, h1;
int slt_pattern_len;
int dpc, opc, slc;
int li;
int i,j,k;
li = buf[2] & 0x3f;
service_indicator = buf[3] & 0xf;
subservice_field = (buf[3] & 0xf0) >> 4;
if(variant(m)==ITU_SS7)
{
dpc = buf[4] | ((buf[5] & 0x3f) << 8);
opc = ((buf[5] & 0xc0) >> 6) | (buf[6] << 2) | ((buf[7] & 0x0f) << 10);
slc = (buf[7] & 0xf0) >> 4;
}else /* CHINA SS7 */ /* by lin.miao@openvox.cn */
{
dpc = buf[4] | ((buf[5] & 0xff) << 8) | ((buf[6] & 0xff) << 16);
opc = buf[7] | ((buf[8] & 0xff) << 8) | ((buf[9] & 0xff) << 16);
slc = buf[10] & 0x0f;
}
if (m->subservice == -1) {
m->subservice = subservice_field;
fifo_log(m, LOG_NOTICE, " Using subservice field from incoming MSU: 0x%x\n", subservice_field);
}
switch(service_indicator) {
case 0x0:
/* Signalling network management messages. */
if(variant(m)==ITU_SS7) {
h0 = buf[8] & 0xf;
h1 = (buf[8] & 0xf0) >> 4;
} else {
h0 = buf[11] & 0xf;
h1 = (buf[11] & 0xf0) >> 4;
}
tm = findtargetslink(m, slc);
fifo_log(m, LOG_DEBUG, "Signalling network management, h0=%d, h1=%d, targetslink '%s'\n", h0, h1, tm ? tm->name : "(unknown)");
if (!tm) {
fifo_log(m, LOG_DEBUG, "Target signalling link %d not found, received on '%s'\n", slc, m->name);
break;
}
if (h0 == 1) { /* CHM - changeover management */
}
else if (h0 == 7 && h1 == 1) {
fifo_log(m, LOG_DEBUG, "Received tra on '%s', sls %d\n", m->name, slc);
}
break;
case 0x1:
/* Signalling network testing and maintenance messages. (SLTM) */
if(li < 7) {
fifo_log(m, LOG_NOTICE, "Got short SLTM/SLTA (no h0/h1/len), li=%d on link '%s'.\n", li, m->name);
return;
}
if(variant(m)==ITU_SS7) {
h0 = buf[8] & 0xf;
h1 = (buf[8] & 0xf0) >> 4;
slt_pattern_len = (buf[9] & 0xf0) >> 4;
} else {
h0 = buf[11] & 0xf;
h1 = (buf[11] & 0xf0) >> 4;
slt_pattern_len = (buf[12] & 0xf0) >> 4;
}
if(li < 7 + slt_pattern_len) {
fifo_log(m, LOG_NOTICE, "Got short SLTM/SLTA (short pattern), li=%d, "
"slt_len=%d on link '%s'.\n", li, slt_pattern_len, m->name);
return;
}
if(h0 == 0x1 && h1 == 0x1) {
/* signalling link test message. */
/* Queue a signalling link test acknowledgement message. (SLTA) */
unsigned char message_slta[21];
int subservice = m->subservice;
if (subservice == -1)
subservice = 0x8;
mtp3_put_label(slc, variant(m), dpc, opc, message_slta);
if(variant(m)==ITU_SS7) {
message_slta[4] = 0x21;
message_slta[5] = slt_pattern_len << 4;
memcpy(&(message_slta[6]), &(buf[10]), slt_pattern_len);
fifo_log(m, LOG_DEBUG, "Got SLTM, sending SLTA '%s', state=%d.\n", m->name, m->state);
mtp2_queue_msu(m, (subservice << 4) | 1, message_slta, 6 + slt_pattern_len);
} else { /* CHINA SS7 */
message_slta[7] = 0x21;
message_slta[8] = slt_pattern_len << 4;
memcpy(&(message_slta[9]), &(buf[13]), slt_pattern_len);
mtp2_queue_msu(m, (subservice << 4) | 1, message_slta, 9 + slt_pattern_len);
}
} else if(h0 == 0x1 && h1 == 0x2) {
/* signalling link test acknowledgement message. */
/* Clear the Q.707 timer T1, since the SLTA was received. */
if(m->sltm_t1 != -1) {
mtp_sched_del(mtp2_sched, m->sltm_t1);
m->sltm_t1 = -1;
}
/* Q.707 (2.2) conditions for acceptance of SLTA. */
if(variant(m)==ITU_SS7)
i = memcmp(sltm_pattern, &(buf[10]), sizeof(sltm_pattern));
else /* CHINESE SS7 */
i = memcmp(sltm_pattern, &(buf[13]), sizeof(sltm_pattern));
if(slc == m->sls &&
opc == linkpeerpc(m) && dpc == this_host->opc &&
0 == i ) {
fifo_log(m, LOG_DEBUG, "Got valid SLTA response on link '%s', state=%d.\n", m->name, m->state);
l4up(m);
} else {
if(m->sltm_tries == 1) {
fifo_log(m, LOG_WARNING, "Received invalid SLTA response (slc=%d,opc=%d,dpc=%d), trying again on link '%s'.\n", slc, opc, dpc, m->name);
mtp3_send_sltm(m);
m->sltm_tries = 2;
} else {
fifo_log(m, LOG_ERROR, "Received invalid SLTA response, faulting link on link '%s'.\n", m->name);
mtp3_link_fail(m, 0);
}
}
} else {
/* Spare. */
fifo_log(m, LOG_NOTICE, "Got unknown/spare signalling network testing "
"and maintenance message code H0=0x%x/H1=0x%x on link '%s'.\n", h0, h1, m->name);
}
break;
case SS7_PROTO_SCCP:
deliver_l4(m, &(buf[4]), (li == 63 ? len - 4 : li - 1), MTP_EVENT_SCCP);
break;
case SS7_PROTO_ISUP:
deliver_l4(m, &(buf[4]), (li == 63 ? len - 4 : li - 1), MTP_EVENT_ISUP);
break;
}
}
/* MTP2 reading of signalling units.
* The buffer pointer is only valid until return from this function, so
* the data must be copied out as needed.
*/
static void mtp2_read_su(mtp2_t *m, unsigned char *buf, int len) {
int i = 0;
int res;
unsigned char nextbyte;
for(;;) {
while(m->h_rx.bits <= 24 && i < len) {
nextbyte = buf[i++];
/* Log the byte for debugging link errors. */
m->backbuf[m->backbuf_idx] = nextbyte;
m->backbuf_idx = (m->backbuf_idx + 1) % sizeof(m->backbuf);
fasthdlc_rx_load_nocheck(&(m->h_rx), nextbyte);
m->readcount++;
if(m->h_rx.state == 0) {
/* Q.703 (10.2.3): Octet counting mode. */
m->emon_ncount = (m->emon_ncount + 1) % 16;
if(m->emon_ncount == 0) {
mtp2_emon_count_error(m);
}
}
}
res = fasthdlc_rx_run(&(m->h_rx));
if(res & RETURN_DISCARD_FLAG) {
/* Some problem, like 7 one-bits in a row, or framesize not dvisible by
8 bits. The fasthdlc now enters a state looking for the next flag
(octet counting mode). */
char msg[80];
sprintf(msg, "MTP2 bitstream frame format error, entering octet counting mode");
mtp2_bad_frame(m, msg);
mtp2_octet_counting(m);
m->rx_len = 0;
m->rx_crc = 0xffff;
} else if(res & RETURN_EMPTY_FLAG) {
if(i >= len) {
/* No more data for now. */
break;
}
/* Else we are skipping bits looking for a flag (Q.703 "octet counting
mode"). */
} else if(res & RETURN_COMPLETE_FLAG) {
if(m->rx_len == 0) {
/* Q.703: Multiple flags in sequence are allowed (though
discouraged). */
} else if(m->rx_len < 5) {
/* Q.703: A frame must be at least 5 bytes (plus one for the flag). If
not, the frame is in error. */
char msg[80];
sprintf(msg, "Short MTP2 frame len %d < 5", m->rx_len);
mtp2_bad_frame(m, msg);
} else {
if(m->rx_crc == 0xf0b8) {
mtp2_good_frame(m, m->rx_buf, m->rx_len-2);
} else {
char msg[80];
sprintf(msg, "MTP2 CRC error (CRC=0x%x != 0xf0b8)", m->rx_crc);
mtp2_bad_frame(m, msg);
}
}
m->rx_len = 0;
m->rx_crc = 0xffff;
} else {
/* Got a data byte. */
/* Q.703: If more than 272+7 bytes are seen in a frame, discard it and
enter "octet counting mode". */
if(m->rx_len >= 272 + 7) {
/* Switch state into "looking for a frame". */
char msg[80];
sprintf(msg, "Overlong MTP2 frame, entering octet counting mode");
m->h_rx.state = 0;
mtp2_bad_frame(m, msg);
mtp2_octet_counting(m);
m->rx_len = 0;
m->rx_crc = 0xffff;
} else {
m->rx_buf[m->rx_len++] = res;
m->rx_crc = PPP_FCS(m->rx_crc, res);
}
}
}
}
static void mtp2_fetch_zap_event(mtp2_t *m) {
int x = 0;
int res;
res = io_get_zaptel_event(m->fd, &x);
fifo_log(m, LOG_NOTICE, "Got event on link '%s': %d (%d/%d).\n", m->name, x, res, errno);
}
/* Find a frame to transmit and put it in the transmit buffer.
Q.703 (11.2.2): Pick a frame in descending priority as
1. Link status signal unit.
2. Requested retransmission of message signal unit.
3. New message signal unit.
4. Fill-in signal unit.
5. Flag [but we can always send fill-in signal unit].
*/
static void mtp2_pick_frame(mtp2_t *m)
{
switch(m->state) {
case MTP2_DOWN:
/* Send SIOS. */
m->tx_len = 4;
m->tx_buffer[0] = m->send_bsn | (m->send_bib << 7);
m->tx_buffer[1] = m->retrans_last_sent | (m->send_fib << 7);
m->tx_buffer[2] = 1; /* Length 1, meaning LSSU. */
m->tx_buffer[3] = 3; /* 3 is indication 'SIOS'. */
return;
case MTP2_NOT_ALIGNED:
/* Send SIO. */
m->tx_len = 4;
m->tx_buffer[0] = m->send_bsn | (m->send_bib << 7);
m->tx_buffer[1] = m->retrans_last_sent | (m->send_fib << 7);
m->tx_buffer[2] = 1; /* Length 1, meaning LSSU. */
m->tx_buffer[3] = 0; /* 0 is indication 'SIO'. */
return;
case MTP2_ALIGNED:
case MTP2_PROVING:
/* Send SIE or SIN. */
m->tx_len = 4;
m->tx_buffer[0] = m->send_bsn | (m->send_bib << 7);
m->tx_buffer[1] = m->retrans_last_sent | (m->send_fib << 7);
m->tx_buffer[2] = 1; /* Length 1, meaning LSSU. */
m->tx_buffer[3] = 2;
return;
case MTP2_READY:
case MTP2_INSERVICE:
/* Frame selection. */
/* If we have something in the retransmission buffer, send it. This
also handles sending new MSUs, as they are simply appended to the
retransmit buffer. */
if(m->retrans_seq != -1) {
/* Send retransmission. */
memcpy(m->tx_buffer,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -