⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mtp.c

📁 asterisk1.4.6版本下 7#信令驱动 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
      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 + -