📄 sdt.c
字号:
* ------------------------------------------------------------------------- * * State Machine * * ------------------------------------------------------------------------- */STATIC INLINE intsdt_aerm_su_in_error(queue_t *q, struct sdt *s){ int err; if (s->statem.aerm_state == SDT_STATE_MONITORING) { s->statem.Ca++; if (s->statem.Ca == s->statem.Ti) { s->statem.aborted_proving = 1; if ((err = sdt_iac_abort_proving_ind(q, s))) { s->statem.Ca--; return (err); } s->statem.aerm_state = SDT_STATE_IDLE; } } return (QR_DONE);}STATIC INLINE intsdt_aerm_correct_su(queue_t *q, struct sdt *s){ int err; if (s->statem.aerm_state == SDT_STATE_IDLE) { if (s->statem.aborted_proving) { if ((err = sdt_iac_correct_su_ind(q, s))) return (err); s->statem.aborted_proving = 0; } } return (QR_DONE);}STATIC INLINE intsdt_suerm_start(queue_t *q, struct sdt *s){ s->statem.Cs = 0; s->statem.Ns = 0; s->statem.suerm_state = SDT_STATE_IN_SERVICE; return (QR_DONE);}STATIC INLINE voidsdt_suerm_stop(queue_t *q, struct sdt *s){ s->statem.suerm_state = SDT_STATE_IDLE;}STATIC INLINE intsdt_suerm_su_in_error(queue_t *q, struct sdt *s){ int err; if (s->statem.suerm_state == SDT_STATE_IN_SERVICE) { s->statem.Cs++; if (s->statem.Cs >= s->config.T) { if ((err = sdt_lsc_link_failure_ind(q, s))) { s->statem.Ca--; return (err); } s->statem.suerm_state = SDT_STATE_IDLE; return (QR_DONE); } s->statem.Ns++; if (s->statem.Ns >= s->config.D) { s->statem.Ns = 0; if (s->statem.Cs) s->statem.Cs--; } } return (QR_DONE);}STATIC INLINE voidsdt_eim_su_in_error(queue_t *q, struct sdt *s){ if (s->statem.eim_state == SDT_STATE_MONITORING) s->statem.interval_error = 1;}STATIC INLINE voidsdt_suerm_correct_su(queue_t *q, struct sdt *s){ if (s->statem.suerm_state == SDT_STATE_IN_SERVICE) { s->statem.Ns++; if (s->statem.Ns >= s->config.D) { s->statem.Ns = 0; if (s->statem.Cs) s->statem.Cs--; } }}STATIC INLINE voidsdt_eim_correct_su(queue_t *q, struct sdt *s){ if (s->statem.eim_state == SDT_STATE_MONITORING) s->statem.su_received = 1;}STATIC INLINE intsdt_eim_start(queue_t *q, struct sdt *s){ s->statem.Ce = 0; s->statem.interval_error = 0; s->statem.su_received = 0; sdt_timer_start(s, t8); s->statem.eim_state = SDT_STATE_MONITORING; return (QR_DONE);}STATIC INLINE voidsdt_eim_stop(queue_t *q, struct sdt *s){ s->statem.eim_state = SDT_STATE_IDLE; sdt_timer_stop(s, t8);}STATIC INLINE intsdt_daedr_correct_su(queue_t *q, struct sdt *s){ sdt_eim_correct_su(q, s); sdt_suerm_correct_su(q, s); return sdt_aerm_correct_su(q, s);}STATIC INLINE intsdt_daedr_su_in_error(queue_t *q, struct sdt *s){ int err; sdt_eim_su_in_error(q, s); if ((err = sdt_suerm_su_in_error(q, s))) return (err); if ((err = sdt_aerm_su_in_error(q, s))) return (err); return (QR_DONE);}STATIC INLINE intsdt_daedr_received_bits(queue_t *q, struct sdt *s, mblk_t *mp){ sdt_path_t *rx = &s->rx; int err, pos, match = 0, len = msgdsize(mp); int hlen = (s->option.popt & SS7_POPT_XSN) ? 6 : 3; if (rx->cmp) { if (len < hlen + 3 && len >= hlen && len == msgdsize(rx->cmp)) for (match = 1, pos = 0; pos < len; pos++) if (!(match = (mp->b_rptr[pos] == rx->cmp->b_rptr[pos]))) break; if (match) { rx->repeat++; s->stats.rx_sus_compressed++; freemsg(mp); sdt_daedr_correct_su(q, s); return (QR_ABSORBED); } else if (rx->repeat > 0 && (err = sdt_rc_signal_unit_ind(q, s, xchg(&rx->cmp, NULL), xchg(&rx->repeat, 0))) != QR_ABSORBED) goto overflow; } if (!match && len < hlen + 3 && (rx->cmp || (rx->cmp = allocb(len, BPRI_MED)))) { bcopy(mp->b_rptr, rx->cmp->b_rptr, len); rx->cmp->b_wptr = rx->cmp->b_rptr + len; rx->repeat = 0; } sdt_daedr_correct_su(q, s); if ((err = sdt_rc_signal_unit_ind(q, s, mp, 1)) == QR_ABSORBED) return (QR_ABSORBED); overflow: s->stats.rx_buffer_overflows++; return (err);}#if 0STATIC INLINE intsdt_daedt_transmission_request(queue_t *q, struct sdt *s){ return sdt_txc_transmission_request_ind(q, s);}#endif/* * ======================================================================== * * Soft-HDLC * * ======================================================================== */#define SDT_TX_STATES 5#define SDT_RX_STATES 14#define SDT_TX_BUFSIZE PAGE_SIZE#define SDT_RX_BUFSIZE PAGE_SIZE#define SDT_CRC_TABLE_LENGTH 512#define SDT_TX_TABLE_LENGTH (2* SDT_TX_STATES * 256)#define SDT_RX_TABLE_LENGTH (2* SDT_RX_STATES * 256)struct tx_entry __attribute__ ((packed));typedef struct tx_entry { uint bit_string:10; /* the output string */ uint bit_length:4; /* length in excess of 8 bits of output string */ uint state:3; /* new state */} tx_entry_t;struct rx_entry __attribute__ ((packed));typedef struct rx_entry { uint bit_string:16; uint bit_length:4; uint state:4; uint sync:1; uint hunt:1; uint flag:1; uint idle:1;} rx_entry_t;typedef uint16_t bc_entry_t;STATIC bc_entry_t *bc_table = NULL;STATIC tx_entry_t *tx_table = NULL;STATIC rx_entry_t *rx_table = NULL;// STATIC rx_entry_t *rx_table7 = NULL;STATIC size_t bc_order = 0;STATIC size_t tx_order = 0;STATIC size_t rx_order = 0;STATIC INLINE tx_entry_t *tx_index8(uint j, uint k){ return &tx_table[(j << 8) | k];}#if 0STATIC INLINE rx_entry_t *rx_index7(uint j, uint k){ return &rx_table7[(j << 8) | k];}#endifSTATIC INLINE rx_entry_t *rx_index8(uint j, uint k){ return &rx_table[(j << 8) | k];}#ifdef _DEBUG#if 0STATIC INLINE voidprintb(uint8_t byte){ uint8_t mask = 0x80; while (mask) { if (mask & byte) printd(("1")); else printd(("0")); }}STATIC INLINE voidprintbs(uint str, uint len){ uint mask = (1 << len); while (mask >>= 1) { if (mask & str) printd(("1")); else printd(("0")); }}STATIC INLINE voidprintr(rx_entry_t * r){ printd(("rx(%2d) %d%d%d%d ", r->state, r->flag, r->sync, r->hunt, r->idle)); printbs(r->bit_string, r->bit_length); printd(("\n"));}STATIC INLINE voidprintt(tx_entry_t * t){ printd(("tx(%2d) ", t->state)); printbs(t->bit_string, t->bit_length + 8); printd(("\n"));}#endif#elseSTATIC INLINE voidprintb(uint8_t byte){}STATIC INLINE voidprintr(rx_entry_t * r){}STATIC INLINE voidprintt(tx_entry_t * t){}#endif/* * TX REPEAT * ---------------------------------------- * Set up the FISU/LSSU repeat buffer for a new message for transmission. * * We need to set up the repeat buffer with every new message. The repeat * buffer contains a FISU for transmitted MSUs (if non-PCR). It contains the * FISU, LSSU or 2-byte LSSU for transmitted FISUs and LSSUs. For SIBs it * contains a FISU (if non-PCR), for other LSSUs it contains the LSSU. */STATIC intsdt_tx_repeat(queue_t *q, struct sdt *s, mblk_t *mp){ mblk_t *cp; int len, hlen, clen; if ((len = msgdsize(mp)) < (hlen = (s->option.popt & SS7_POPT_XSN) ? 6 : 3)) { ptrace(("%s: %p: ERROR: user violated minimum size\n", MOD_NAME, s)); goto dont_repeat; } if (len > hlen + 2 || ((len == hlen + 1 || len == hlen + 2) && (mp->b_rptr[hlen] & 0x7) == 5)) { /* MSU or SIB */ if (s->option.popt & SS7_POPT_PCR) goto dont_repeat; clen = hlen; } else { /* FISU or LSSU */ clen = len; } if (!(cp = s->tx.cmp) && !(cp = s->tx.cmp = ss7_allocb(q, clen, BPRI_MED))) return (-ENOBUFS); bcopy(mp->b_rptr, cp->b_rptr, clen); cp->b_wptr = cp->b_rptr + clen; if (!(s->option.popt & SS7_POPT_XSN)) ((uint8_t *) cp->b_rptr)[2] = clen - hlen; else ((uint16_t *) cp->b_rptr)[2] = clen - hlen; return (0); dont_repeat: if (s->tx.cmp) freemsg(xchg(&s->tx.cmp, NULL)); return (0);}/* * TX BUFFER * ---------------------------------------- * Pick up another TX buffer from the queue or a repeat frame. */STATIC mblk_t *sdt_tx_buffer(queue_t *q, struct sdt *s){ mblk_t *dp = NULL; psw_t flags; /* lock down while we traverse queue */ spin_lock_irqsave(&s->qlock, flags); { mblk_t *mp; for (mp = s->iq->q_first; mp; mp = mp->b_next) { switch (mp->b_datap->db_type) { case M_DATA: if (sdt_tx_repeat == 0) { dp = mp; rmvq(s->iq, dp); } break; case M_PROTO: if (*((ulong *) mp->b_rptr) != SDT_DAEDT_TRANSMISSION_REQ) continue; if (sdt_tx_repeat == 0) { dp = mp->b_cont; rmvq(s->iq, mp); freeb(mp); } break; default: continue; } break; } } spin_unlock_irqrestore(&s->qlock, flags); if (!dp && (dp = s->tx.cmp)) { fixme(("Peg some stats\n")); } return (dp);}/* * TX BITSTUFF * ---------------------------------------- * Bitstuff an octet and shift residue for output. */STATIC INLINE voidsdt_tx_bitstuff(sdt_path_t * tx, unsigned char byte){ tx_entry_t *t = tx_index8(tx->state, byte); tx->state = t->state; tx->residue |= t->bit_string << tx->rbits; tx->rbits += t->bit_length + 8;}#define TX_MODE_IDLE 0 /* generating mark idle */#define TX_MODE_FLAG 1 /* generating flag idle */#define TX_MODE_BOF 2 /* generating bof flag */#define TX_MODE_MOF 3 /* generating frames */#define TX_MODE_BCC 4 /* generating bcc bytes *//* * TX BLOCK * ---------------------------------------- * Generate blocks for transmission. We generate entire transmit blocks. If * there are not sufficient messages to build the transmit blocks we will * repeat FISU/LSSU or idle flags. */STATIC voidsdt_tx_block(queue_t *q, struct sdt *s){ mblk_t *bp; register sdt_path_t *tx = &s->tx; sdt_stats_t *stats = &s->stats;#if 0 int bits = (s->config.iftype == SDL_TYPE_DS0A) ? 7 : 8;#else const int bits = 8;#endif while (canputnext(s->iq)) { if (!(bp = ss7_allocb(q, s->config.b, BPRI_MED))) break; /* bufcall will bring us back */ if (tx->mode == TX_MODE_IDLE || tx->mode == TX_MODE_FLAG) { if (!tx->nxt) { next_message: if (tx->msg && tx->msg != tx->cmp) freemsg(tx->msg); if ((tx->msg = tx->nxt = sdt_tx_buffer(q, s))) tx->mode = TX_MODE_BOF; } } /* check if transmission block complete */ while (bp->b_wptr < bp->b_rptr + s->config.b) { /* drain residue bits, if necessary */ if (tx->rbits >= bits) { drain_rbits: /* drain residue bits */ if (bits == 8) *bp->b_wptr++ = tx->residue; else *bp->b_wptr++ = tx->residue & 0x7f; tx->residue >>= bits; tx->rbits -= bits; continue; } switch (tx->mode) { case TX_MODE_IDLE: /* mark idle */ tx->residue |= 0xff << tx->rbits; tx->rbits += 8; goto drain_rbits; case TX_MODE_FLAG: /* idle flags */ tx->residue |= 0x7e << tx->rbits; tx->rbits += 8; goto drain_rbits; case TX_MODE_BOF: /* add opening flag (also closing flag) */ switch (s->config.f) { case SDT_FLAGS_ONE: tx->residue |= 0x7e << tx->rbits; tx->rbits += 8; break; case SDT_FLAGS_SHARED: tx->residue |= 0x3f7e << tx->rbits; tx->rbits += 15; break; case SDT_FLAGS_TWO: tx->residue |= 0x7e7e << tx->rbits; tx->rbits += 16; break; default: case SDT_FLAGS_THREE: tx->residue |= 0x7e7e7e << tx->rbits; tx->rbits += 24; break; } tx->state = 0; tx->bcc = 0x00ff; tx->mode = TX_MODE_MOF; goto drain_rbits; case TX_MODE_MOF: /* transmit frame bytes */ if (tx->nxt->b_rptr < tx->nxt->b_wptr || (tx->nxt = tx->nxt->b_cont)) { /* continuing in message */ uint byte = *(tx->nxt->b_rptr)++; tx->bcc = (tx->bcc >> 8) ^ bc_table[(tx->bcc ^ byte) & 0x00ff]; sdt_tx_bitstuff(tx, byte); stats->tx_bytes++; } else { /* finished message: add 1st bcc byte */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -