/* * Mobicents, Communications Middleware * * Copyright (c) 2008, Red Hat Middleware LLC or third-party * contributors as * indicated by the @author tags or express copyright attribution * statements applied by the authors. All third-party contributions are * distributed under license by Red Hat Middleware LLC. * * This copyrighted material is made available to anyone wishing to use, modify, * copy, or redistribute it subject to the terms and conditions of the GNU * Lesser General Public License, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License * for more details. * * * You should have received a copy of the GNU Lesser General Public License * along with this distribution; if not, write to: * Free Software Foundation, Inc. * 51 Franklin Street, Fifth Floor * * Boston, MA 02110-1301 USA */ package org.mobicents.media.server.impl.resource.zap; import org.mobicents.media.server.impl.resource.ss7.HdlcState; import org.apache.log4j.Logger; /** * * @author kulikov */ public class Mtp2 { protected final static int MTP_MAX_PCK_SIZE = 300; private final static int ZAP_BUF_SIZE = 16; public final static int STATE_DOWN = 0; public final static int STATE_READY = 1; public final static int STATE_INSERVICE = 2; private String channelName; private int state; /* Counts of raw bytes read and written, used to timestamp raw dumps. Make them double to avoid overflow for quite a while. */ private double readcount, writecount; /* Sequence numbers and indicator bits to be sent in signalling units. */ private int send_fib; private int send_bsn, send_bib; /* Send initial SLTM? */ private int send_sltm; /* Timeslot for signalling channel */ private int schannel; private int slinkno; private int sls; private int subservice; /* Receive buffer. */ private byte[] rx_buf = new byte[272 + 7]; private int rx_len; private int rx_crc; /* Transmit buffer. */ private byte[] tx_buffer = new byte[272 + 7 + 5]; private int tx_len; private int tx_sofar; private int tx_do_crc; /* Flag used to handle writing CRC bytes */ private int tx_crc; /* Zaptel transmit buffer. */ private byte[] zap_buf = new byte[ZAP_BUF_SIZE]; int zap_buf_full; /* HDLC encoding and decoding state. */ private HdlcState h_rx; private HdlcState h_tx; /* Last few raw bytes received, for debugging link errors. */ private byte[] backbuf = new byte[36]; int backbuf_idx; /* Retransmit buffer. */ private DataBuffer[] retrans_buf = new DataBuffer[128]; /* Retransmit counter; if this is != -1, it means that retransmission is taking place, with this being the next sequence number to retransmit. */ private int retrans_seq; /* Last sequence number ACK'ed by peer. */ private int retrans_last_acked; /* Last sequence number sent to peer. */ private int retrans_last_sent; /* Counter for signal unit/alignment error rate monitors (Q.703 (10)). */ private int error_rate_mon; /* Counters matching the D and N values of the error rate monitors. */ private int emon_ncount, emon_dcount; /* Counter for bad BSN */ private int bsn_errors; /* Q.703 timer T1 "alignment ready" (waiting for peer to end initial alignment after we are done). */ private int mtp2_t1; /* Q.703 timer T2 "not aligned" (waiting to receive O, E, or N after sending O). */ private int mtp2_t2; /* Q.703 timer T3 "aligned" (waiting to receive E or N after sending E or N). */ private int mtp2_t3; /* Q.703 timer T4 "proving period" - proving time before ending own initial alignment. */ private int mtp2_t4; /* Q.703 timer T7 "excessive delay of acknowledgement" . */ private int mtp2_t7; /* Set true when SLTA is received and User Parts (ie. ISUP) is notified that the link is now in service. */ private int level4_up; /* Hm, the rest is actually MTP3 state. Move to other structure, or rename this structure. */ private int sltm_t1; /* Timer T1 for SLTM (Q.707) */ private int sltm_t2; /* Timer T2 for SLTM (Q.707) */ private int sltm_tries; /* For SLTM retry (Q.707 (2.2)) */ /* Q.704 timer T17, "initial alignment restart delay". */ private int mtp3_t17; private final static Logger logger = Logger.getLogger(Mtp2.class); public Mtp2(String channelName) { this.channelName = channelName; } private int MTP_NEXT_SEQ(int bsn) { throw new UnsupportedOperationException("Not yet implemented"); } private void mtp2_good_frame(byte[] buf, int len) { int fsn, fib, bsn, bib; int li; /* Count this frame into the error rate monitor counters. */ //mtp2_error_mon_count_frame(m); if (state == STATE_DOWN) { return; } bsn = buf[0] & 0x7f; bib = buf[0] >> 7; fsn = buf[1] & 0x7f; fib = buf[1] >> 7; li = buf[2] & 0x3f; if (li + 3 > len) { logger.warn("Got unreasonable length indicator " + li + " (len=" + len + ") on link " + channelName); return; } if (li == 1 || li == 2) { /* Link status signal unit. */ mtp2_process_lssu(buf, fsn, fib); return; } /* Process the BSN of the signal unit. According to Q.703 (5), only FISU and MSU should have FSN and BSN processing done. */ if (state != STATE_INSERVICE) { if (state == STATE_READY) { t1_stop(); t7_stop(); send_fib = bib; send_bsn = fsn; send_bib = fib; // retrans_last_acked = fsn;xxx // retrans_last_sent = fsn;xxx retrans_last_acked = bsn;//xxx error_rate_mon = 0; emon_dcount = 0; emon_ncount = 0; level4_up = 0; /* Send TRA (traffic restart allowed) immediately, since we have no routing capabilities that could be prohibited/restricted. */ } else { return; } } else if (state == STATE_READY) { t1_stop(); t7_stop(); } /* 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 ((retrans_last_acked <= retrans_last_sent && (bsn < retrans_last_acked || bsn > retrans_last_sent)) || (retrans_last_acked > retrans_last_sent && (bsn < retrans_last_acked && bsn > retrans_last_sent))) { /* They asked for a retransmission of a sequence number not available. */ logger.warn("Received illegal BSN=" + bsn + " (retrans=" + retrans_last_acked +"," + retrans_last_sent + ") on link "+ channelName +", len=" + len); /* ToDo: Fault the link if this happens again within the next two SUs, see second last paragraph of Q.703 (5.3.1). */ if (bsn_errors++ > 2) { bsn_errors = 0; mtp3_link_fail(1); } return; } bsn_errors = 0; /* Reset timer T7 if new acknowledgement received (Q.703 (5.3.1) last paragraph). */ if (retrans_last_acked != bsn) { t7_stop(); retrans_last_acked = bsn; if (retrans_last_acked != retrans_last_sent) { mtp2_t7_start(); } } if (bib != send_fib) { /* Received negative acknowledge, start re-transmission. */ send_fib = bib; if (bsn == retrans_last_sent) { /* Nothing to re-transmit. */ retrans_seq = -1; } else { 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 != send_bsn) { /* This indicates the loss of a message. */ if (fib == send_bib) { /* Send a negative acknowledgement, to request retransmission. */ if (send_bib == 1) { send_bib = 0; } else { send_bib= 0; } // send_bib = !send_bib; } } } else { /* Message signal unit. */ /* Process the FSN of the received frame. */ if (fsn == send_bsn) { /* Q.703 (5.2.2.c.i): Redundant retransmission. */ return; } else if (fsn == MTP_NEXT_SEQ(send_bsn)) { /* Q.703 (5.2.2.c.ii). */ if (fib == send_bib) { /* Successful frame reception. Do explicit acknowledge on next frame. */ 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 == send_bib) { /* Send a negative acknowledgement, to request retransmission. */ if (send_bib == 1) { send_bib = 0; } else { send_bib= 0; } // send_bib = !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) { logger.warn("Got short MSU (no label), li=" + li +" on link " + channelName); return; } process_msu(buf, len); } } private void mtp2_process_lssu(byte[] buf, int fsn, int fib) { throw new UnsupportedOperationException("Not yet implemented"); } private void mtp2_t7_start() { throw new UnsupportedOperationException("Not yet implemented"); } private void mtp3_link_fail(int i) { throw new UnsupportedOperationException("Not yet implemented"); } private void process_msu(byte[] buf, int len) { throw new UnsupportedOperationException("Not yet implemented"); } private void t1_stop() { } private void t7_stop() { } } class DataBuffer { private byte[] data = new byte[Mtp2.MTP_MAX_PCK_SIZE]; private int len; public DataBuffer(byte[] data, int len) { this.data = data; this.len = len; } public byte[] getData() { return data; } public int len() { return len; } }