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

📄 l4isup.c

📁 asterisk1.4.6版本下 7#信令驱动 源码
💻 C
📖 第 1 页 / 共 5 页
字号:
    ast_log(LOG_DEBUG, "Phonenumber too large to fit in parameter, "
            "len %d < %d.\n", plen, result_len);
    return -1;
  }

  param[0] = (is_odd << 7) | (is_international ? 4 : 3);
  param[1] = 0x10; /* Internal routing allowed, ISDN number plan */

  if(isup_phonenum_digits(number, 1, nlen, param) == -1) {
    return -1;
  }
  return result_len;            /* Success */
}

/* Encode a phone number in ISUP "Called Party Number" format. (Q.763 (3.9))
   Returns encoded length on success, -1 on error. */
int isup_called_party_num_encode_no_st(char *number, unsigned char *param,
				       int plen) {
  int nlen;
  int is_odd;
  int is_international;
  int result_len;

  if(isup_phonenum_check(&number, &nlen, &is_international) == -1) {
    return -1;
  }

  /* We do not termminate the number with ST to signify that the number is incomplete
     (overlapped dialing). */
  is_odd = (nlen) % 2;
  /* Need room for two header bytes + all of the (nlen) digits. */
  result_len = 2 + (nlen + 1)/2;
  if(result_len > plen) {
    ast_log(LOG_DEBUG, "Phonenumber too large to fit in parameter, "
            "len %d < %d.\n", plen, result_len);
    return -1;
  }

  param[0] = (is_odd << 7) | (is_international ? 4 : 3);
  param[1] = 0x10; /* Internal routing allowed, ISDN number plan */

  if(isup_phonenum_digits(number, 0, nlen, param) == -1) {
    return -1;
  }
  return result_len;            /* Success */
}

/* Encode a phone number in ISUP "Calling Party Number" format. (Q.763 (3.10))
   Returns encoded length on success, -1 on error. */
int isup_calling_party_num_encode(char *number, int pres_restr,
				  unsigned char *param, int plen) {
  int nlen;
  int is_odd;
  int is_international;
  int result_len;

  if(isup_phonenum_check(&number, &nlen, &is_international) == -1) {
    return -1;
  }

  is_odd = nlen % 2;
  /* Need room for two header bytes + all of the nlen digits. */
  result_len = 2 + (nlen + 1)/2;
  if(result_len > plen) {
    ast_log(LOG_DEBUG, "Phonenumber too large to fit in parameter, "
            "len %d < %d.\n", plen, result_len);
    return -1;
  }

  param[0] = (is_odd << 7) | (is_international ? 4 : 3);
  param[1] = 0x13; /* Number complete; ISDN number plan; network provided */
  /* 0x11: Number complete; ISDN number plan; user provided, verified and passed */
  if(pres_restr) {
    param[1] |= (0x1 << 2);
  }

  if(isup_phonenum_digits(number, 0, nlen, param) == -1) {
    return -1;
  }
  return result_len;            /* Success */
}

static int isup_send_sam(struct ss7_chan *pvt, char* addr, int complete)
{
  unsigned char msg[MTP_MAX_PCK_SIZE];
  int current, varptr;
  unsigned char param[2 + PHONENUM_MAX];
  int res;

  isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_SAM, &current);
  if (complete)
    res = isup_called_party_num_encode(addr, param, sizeof(param));
  else
    res = isup_called_party_num_encode_no_st(addr, param, sizeof(param));
  isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 1, 0);
  /* Param index 1 not used with SAM, change it */
  param[1] = param[0]; res--;
  isup_msg_add_variable(msg, sizeof(msg), &varptr, &current, &param[1], res);
  isup_msg_start_optional_part(msg, sizeof(msg), &varptr, &current);
  isup_msg_end_optional_part(msg, sizeof(msg), &current);

  mtp_enqueue_isup(pvt, msg, current);

  return 0;
}


static int isup_send_iam(struct ast_channel *chan, char *addr, char *rdni, char *dni, int dnilimit) {
  struct ss7_chan *pvt = chan->tech_pvt;
  unsigned char msg[MTP_MAX_PCK_SIZE];
  unsigned char param[2 + PHONENUM_MAX];
  int current, varptr;
  char dnicpy[100]; 
  int pres_restr;
  int res;
  const char *isdn_h324m;
  int h324m_usi=0, h324m_llc=0;
  
  isdn_h324m = pbx_builtin_getvar_helper(chan, "ISDN_H324M");
  if (isdn_h324m) {
    ast_verbose(VERBOSE_PREFIX_3 "chan_ss7: isup_send_iam: ISDN_H324M=%s\n", isdn_h324m);
    if (strstr(isdn_h324m,"USI")) {
      h324m_usi = 1;
    } 
    if (strstr(isdn_h324m,"LLC")) {
      h324m_llc = 1;
    }
    ast_verbose(VERBOSE_PREFIX_3 "chan_ss7: isup_send_iam: h324m_usi=%d, h324m_llc=%d\n", h324m_usi, h324m_llc);
  } else {
    ast_verbose(VERBOSE_PREFIX_3 "chan_ss7: isup_send_iam: ISDN_H324M is not set.\n");
  }

  isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_IAM, &current);

  /* Nature of connection indicators Q.763 (3.35). */
  param[0] = 0x00; /* No sattelite, no continuity check, no echo control */
  isup_msg_add_fixed(msg, sizeof(msg), &current, param, 1);

  /* Forward call indicator Q.763 (3.23). */
  if (h324m_usi || h324m_llc) {
    param[0] = 0xA0; /* No end-to-end method , no interworking, no end-to-end
                        info, ISDN all the way, ISDN required */
  } else {
    param[0] = 0x60; /* No end-to-end method , no interworking, no end-to-end
                        info, ISDN all the way, ISDN not required */
  }
  param[1] = 0x01; /* Originating access ISDN, no SCCP indication */
  isup_msg_add_fixed(msg, sizeof(msg), &current, param, 2);

  /* Calling party's category Q.763 (3.11). */
  param[0] = 0x0a; /* Ordinary calling subscriber */
  //ast_log(LOG_ERROR,"Subcriber is %d",msg);
  isup_msg_add_fixed(msg, sizeof(msg), &current, param, 1);

  /* Transmission medium requirement Q.763 (3.54). */
  if (h324m_usi || h324m_llc) {
    param[0] = 0x02; /* 64 kbit/s unrestricted */
    pvt->is_digital = 1;
  } else {
    param[0] = 0x00; /* Speech */
  }
  isup_msg_add_fixed(msg, sizeof(msg), &current, param, 1);

  /* Called party number Q.763 (3.9). */
  isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 1, 1);

  if (dnilimit > 0 && strlen(dni) > dnilimit) {
    /* Make part of dni */
    strncpy(dnicpy, dni, dnilimit);
    dnicpy[dnilimit] = '\0';
    res = isup_called_party_num_encode_no_st(dnicpy, param, sizeof(param));
  } else {
    res = isup_called_party_num_encode(dni, param, sizeof(param));
  }

  if(res < 0) {
    ast_log(LOG_NOTICE, "Invalid format for phonenumber '%s'.\n", dni);
    request_hangup(chan, AST_CAUSE_INVALID_NUMBER_FORMAT);
    ast_mutex_unlock(&pvt->lock);
    return -1;
  }
  isup_msg_add_variable(msg, sizeof(msg), &varptr, &current, param, res);

  isup_msg_start_optional_part(msg, sizeof(msg), &varptr, &current);

  /* Calling partys number Q.763 (3.10). */
  if((chan->cid.cid_pres & AST_PRES_RESTRICTION) == AST_PRES_RESTRICTED) {
    pres_restr = 1;
  } else {
    pres_restr = 0;
  }
  res = isup_calling_party_num_encode(chan->cid.cid_num, pres_restr,
                                      param, sizeof(param));
  if(res < 0) {
    ast_log(LOG_DEBUG, "Invalid format for calling number, dropped.\n");
  } else {
    isup_msg_add_optional(msg, sizeof(msg), &current, IP_CALLING_PARTY_NUMBER,
                          param, res);
  }
  /* Some switches do not understand H.223. Those switches use Access Transport
   * (Low Layer Compatibility) to signal the video call end-to-end.
   */
  if (h324m_usi) {
    /* User Service Information: Q.763 3.57 */
    param[0] = 0x88; /* unrestricted digital information */
    param[1] = 0x90; /* circuit mode, 64 kbit */
    param[2] = 0xA6; /* UL1, H.223 and H.245 */
    isup_msg_add_optional(msg, sizeof(msg), &current, IP_USER_SERVICE_INFORMATION,
                          param, 3);
  }
  if (h324m_llc) {
    /* Access Transport Q.763 3.3 */
    param[0] = 0x7C; /* unrestricted digital information */
    param[1] = 0x03; /* circuit mode, 64 kbit */
    param[2] = 0x88; /* UL1, H.223 and H.245 */
    param[3] = 0x90; /* UL1, H.223 and H.245 */
    param[4] = 0xA6; /* UL1, H.223 and H.245 */
    isup_msg_add_optional(msg, sizeof(msg), &current, IP_ACCESS_TRANSPORT,
                          param, 5);
  }

  if (*rdni) {
    res = isup_calling_party_num_encode(rdni, pres_restr, param, sizeof(param));
    isup_msg_add_optional(msg, sizeof(msg), &current, IP_REDIRECTING_ORINUM, param, res);  	
    /* ToDo: Pass on RDNIS (and redirection cause when we implement that) as
       ISUP parameters? */
    /* Q.763 3.45 */
    res = isup_calling_party_num_encode(rdni, pres_restr, param, sizeof(param));
    isup_msg_add_optional(msg, sizeof(msg), &current, IP_REDIRECTING_NUMBER, param, res);
    param[0] = 0x31; /* redirecting indicator: call diverted, all redirection information presentation restricted,
			original redirection reason: unknown */
			
    param[1] = 0x31; /* reredicting counter: 1
			redirection reason: unconditional */
			
    isup_msg_add_optional(msg, sizeof(msg), &current, IP_REDIRECTION_INFORMATION, param, 2);
  }

  /* End and send the message. */
  isup_msg_end_optional_part(msg, sizeof(msg), &current);

  mtp_enqueue_isup(pvt, msg, current);
  ast_verbose(VERBOSE_PREFIX_3 "Sent IAM CIC=%-3d  ANI=%s DNI=%s RNI=%s\n", pvt->cic,
	  pres_restr ? "*****" : chan->cid.cid_num,
          dni,
          rdni);

  return 0;
}

/* Assume that we are called with chan->lock held (as ast_call() does). */
static int ss7_call(struct ast_channel *chan, char *addr, int timeout) {
  struct ss7_chan *pvt = chan->tech_pvt;
  char *sep = strchr(addr, '/');
  char rdni[100];
  char dnicpy[100];
  char dni[100];
  int chunk_limit, chunk_sofar=0;
  int res;

  ast_mutex_lock(&pvt->lock);

  ast_log(LOG_DEBUG, "SS7 call, addr=%s, cid=%s(0x%x/%s) CIC=%d. linkset '%s'\n",
          (addr ? addr : "<NULL>"),
          (chan->cid.cid_num ? chan->cid.cid_num : "<NULL>"),
          chan->cid.cid_pres,
          ast_describe_caller_presentation(chan->cid.cid_pres),
	  pvt->cic, pvt->link->linkset->name);

  pvt->addr = addr;
  pvt->attempts = 1;

  if (sep)
    addr = sep+1;
  strcpy(dni, addr);
  strcpy(rdni, chan->cid.cid_rdnis ? chan->cid.cid_rdnis : "");
  sep = strchr(dni, ':');
  if (sep) {
    *sep = '\0';
    strcpy(rdni, sep+1);
  }

  chunk_limit = pvt->link->linkset->dni_chunk_limit;

  pvt->link->linkset->outgoing_calls++;
  res = isup_send_iam(chan, addr, rdni, dni, chunk_limit);
  if (res < 0) {
    ast_log(LOG_WARNING, "SS7 call failed, addr=%s CIC=%d. linkset '%s'\n", (addr ? addr : "<NULL>"), pvt->cic, pvt->link->linkset->name);
    free_cic(pvt);
    ast_mutex_unlock(&pvt->lock);
    return res;
  }

  if (chunk_limit > 0 && strlen(dni) > chunk_limit) {
    while(chunk_sofar < strlen(dni)) {
      strncpy(dnicpy, &dni[chunk_sofar], chunk_limit);
      chunk_sofar += chunk_limit;
      dnicpy[chunk_sofar] = '\0';
      isup_send_sam(pvt, dnicpy, 1);
    }
  }

  pvt->state = ST_SENT_IAM;

  t7_start(chan);

  ast_mutex_unlock(&pvt->lock);

  return 0;
}

static int ss7_hangup(struct ast_channel *chan) {
  struct ss7_chan *pvt = chan->tech_pvt;

  if (!pvt || pvt->cic == -1) {
    decr_usecount();
    ast_update_use_count();
    return 0;
  }
  ast_verbose( VERBOSE_PREFIX_3 "SS7 hangup '%s' CIC=%d Cause=%d (state=%d)\n",
               chan->name, pvt->cic, chan->hangupcause, pvt->state);

  /* Digium insists that ss7_hangup() must be called with chan->lock() held,
     even though it is the wrong thing to do (bug 5051). So we have to unlock
     it on entry and re-lock it on exit to get sane locking semantics. */
  ast_mutex_unlock(&chan->lock);

  /* First remove us from the global circuit list. */
  lock_global();

  ast_mutex_lock(&pvt->lock);
  decr_usecount();


  ast_log(LOG_DEBUG, "SS7 hangup '%s' CIC=%d (state=%d), chan=0x%08lx\n",
	  chan->name, pvt->cic, pvt->state, (unsigned long) chan);

  chan->tech_pvt = NULL;
  pvt->owner = NULL;

  /* Clear all the timers that may hold on to references to chan. This must be
     done while global lock is held to prevent races. */
  t1_clear(pvt);
  t2_clear(pvt);
  t5_clear(pvt);
  t6_clear(pvt);
  t7_clear(pvt);
  t9_clear(pvt);
  t16_clear(pvt);
  t17_clear(pvt);
  t18_clear(pvt);
  t19_clear(pvt);
  t20_clear(pvt);
  t21_clear(pvt);
  t35_clear(pvt);

  if(pvt->state == ST_GOT_REL) {
    isup_send_rlc(pvt);
    ast_setstate(chan, AST_STATE_DOWN);
    free_cic(pvt);
  }
  else if(pvt->state == ST_SENT_REL) {
    t1_start(pvt);
    t5_start(pvt);
  } else if(pvt->state != ST_IDLE) {
    ast_log(LOG_DEBUG, "SS7 hangup '%s' CIC=%d cause=%d\n", chan->name, pvt->cic, chan->hangupcause);
    initiate_release_circuit(pvt, chan->hangupcause);
  }

  if (pvt->echocancel) {
    io_disable_echo_cancellation(pvt->zaptel_fd, pvt->cic);
    pvt->echocancel = 0;
  }
  clear_audiomode(pvt->zaptel_fd);

  ast_mutex_unlock(&pvt->lock);
  unlock_global();

  ast_update_use_count();

  ast_mutex_lock(&chan->lock);  /* See above */

  return 0;
}

static int ss7_answer(struct ast_channel *chan) {
  struct ss7_chan *pvt = chan->tech_pvt;
  unsigned char msg[MTP_MAX_PCK_SIZE];
  int current, varptr;
  unsigned char param[2];

  ast_mutex_lock(&pvt->lock);

  ast_log(LOG_DEBUG, "SS7 answer CIC=%d, pvt->state=%d.\n", pvt->cic, pvt->state);

  /* Send ANM instead of CON if previously sent ACM. */
  if (pvt->state == ST_SENT_ACM) {
    isup_msg_init(msg, sizeof(msg), variant(pvt), this_host->opc, peerpc(pvt), pvt->cic, ISUP_ANM, &current);
    param[0] = 0x14;  /* Subscriber free, ordinary subscriber, no end-to-end */
    param[1] = 0x14;  /* No interworking, no end-to-end, ISDN all the way, no
			 hold, terminating access ISDN, no echo control */
    isup_msg_start_variable_part(msg, sizeof(msg), &varptr, &current, 0, 1);
    isup_msg_start_optional_part(msg, sizeof(msg), &varptr, &current);
    isup_msg_add_optional(msg, sizeof(msg), &current, IP_BACKWARD_CALL_INDICATORS, param, 2);
    isup_msg_end_optional_part(msg, sizeof(msg), &current);
    mtp_enqueue_isup(pvt, msg, current);
  } else if (pvt->state == ST_GOT_IAM) {
    isup_msg_init(msg, sizeof(msg), variant(pvt), 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -