Files
freeswitch/libs/sipcc/core/sipstack/ccsip_register.c
T

3080 lines
101 KiB
C

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <errno.h>
#include "cpr_types.h"
#include "cpr_stdio.h"
#include "cpr_stdlib.h"
#include "cpr_timers.h"
#include "cpr_string.h"
#include "cpr_memory.h"
#include "cpr_ipc.h"
#include "cpr_in.h"
#include "util_string.h"
#include "task.h"
#include "phntask.h"
#include "ccsip_core.h"
#include "ccsip_messaging.h"
#include "phone_debug.h"
#include "ccsip_platform.h"
#include "ccsip_platform_timers.h"
#include "ccsip_macros.h"
#include "ccsip_pmh.h"
#include "ccsip_register.h"
#include "ccsip_task.h"
#include "ccsip_credentials.h"
#include "debug.h"
#include "logmsg.h"
#include "ccsip_pmh.h"
#include "ccsip_credentials.h"
#include "dns_utils.h"
#include "config.h"
#include "sip_common_transport.h"
#include "uiapi.h"
#include "sip_common_regmgr.h"
#include "text_strings.h"
#include "sip_interface_regmgr.h"
#include "phone_platform_constants.h"
#include "ccsip_common_cb.h"
#include "misc_util.h"
extern sipPlatformUITimer_t sipPlatformUISMTimers[];
extern void *new_standby_available;
extern boolean regall_fail_attempt;
extern boolean registration_reject;
extern void ui_set_sip_registration_state(line_t line, boolean registered);
extern void ui_update_registration_state_all_lines(boolean registered);
boolean dump_reg_msg = TRUE;
boolean refresh_reg_msg = FALSE;
static ccsip_register_states_t ccsip_register_state = SIP_REG_IDLE;
/* Need an additional ack timer for the backup proxy */
static cprTimer_t ack_tmrs[MAX_REG_LINES + 1];
ccm_act_stdby_table_t CCM_Active_Standby_Table;
extern ccm_failover_table_t CCM_Failover_Table;
static boolean start_standby_monitor = TRUE;
extern boolean Is794x;
static void show_register_data(void);
#define SIP_REG_TMR_EXPIRE_TICKS 55000 /* msec; re-registration timer */
#define REGISTER_CMD "register"
#define SIP_REG_TMR_ACK_TICKS 32000 /* msec; supervision timer equivalent to Timer F */
static const char *ccsip_register_state_names[] = {
"IDLE",
"REGISTERING",
"REGISTERED",
"UNREGISTERING",
"PRE_FALLBACK",
"IN_FAILOVER",
"POST_FAILOVER",
"STANDBY_FAILOVER",
"NO_CC",
"NO_STANDBY",
"NO_REGISTER"
};
static const char *ccsip_register_reg_state_names[] = {
"NONE",
"IDLE",
"REGISTERING",
"REGISTERED",
"UNREGISTERING",
"PRE_FALLBACK",
"IN_FAILOVER",
"POST_FAILOVER",
"STANDBY_FAILOVER",
"NO_CC",
"NO_STANDBY",
"NO_REGISTER"
};
void ccsip_handle_ev_reg_req(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_reg_cancel(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_unreg_2xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_1xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_2xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_3xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_4xx(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_failure_response(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_tmr_expire(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_tmr_ack(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_tmr_retry(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_unreg_tmr_ack(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_standby_keepalive_tmr_expire(ccsipCCB_t *ccb, sipSMEvent_t *event);
void ccsip_handle_ev_idle_tmr_expire(ccsipCCB_t *ccb, sipSMEvent_t *event);
const char *ccsip_register_state_name(ccsip_register_states_t state);
const char *ccsip_register_reg_state_name(sipRegSMStateType_t state);
const char *sip_util_reg_event2string(sipRegSMEventType_t event);
char *sip_util_reg_state2string(sipRegSMStateType_t state);
void ccsip_register_retry_timer_start(ccsipCCB_t *ccb);
void ccsip_register_cleanup(ccsipCCB_t *ccb, boolean start);
cc_int32_t ccsip_register_cmd(cc_int32_t argc, const char *argv[]);
void ccsip_register_clear_all_logs(void);
boolean ccsip_register_all_registered(void);
/* convert sip line to reg line */
#define SIP_REG_LINE2REGLINE(line) ((line) - (REG_CCB_START))
/* convert reg line to sip line */
#define SIP_REG_REGLINE2LINE(line) ((line) + (REG_CCB_START))
// Date holder
static struct {
boolean valid;
char datestring[MAX_SIP_DATE_LENGTH];
} ccm_date;
static const sipSMEventActionFn_t
gSIPRegSMTable[SIP_REG_STATE_END - SIP_REG_STATE_BASE + 1]
[SIPSPI_REG_EV_END - SIPSPI_REG_EV_BASE + 1] =
{
/* SIP_REG_STATE_IDLE
*/
{
/* E_SIP_REG_REG_REQ */ ccsip_handle_ev_reg_req,
/* E_SIP_REG_CANCEL */ ccsip_handle_ev_default,
/* E_SIP_REG_1xx */ ccsip_handle_ev_default,
/* E_SIP_REG_2xx */ ccsip_handle_ev_default,
/* E_SIP_REG_3xx */ ccsip_handle_ev_default,
/* E_SIP_REG_4xx */ ccsip_handle_ev_default,
/* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_default,
/* E_SIP_REG_TMR_ACK */ ccsip_handle_ev_default,
/* E_SIP_REG_TMR_EXPIRE */ ccsip_handle_ev_idle_tmr_expire,
/* E_SIP_REG_TMR_WAIT */ ccsip_handle_ev_default,
/* E_SIP_REG_TMR_RETRY */ ccsip_handle_ev_default,
/* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
},
/* SIP_REG_STATE_REGISTERING
*/
{
/* E_SIP_REG_REG_REQ */ ccsip_handle_ev_reg_req,
/* E_SIP_REG_CANCEL */ ccsip_handle_ev_reg_cancel,
/* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
/* E_SIP_REG_2xx */ ccsip_handle_ev_2xx,
/* E_SIP_REG_3xx */ ccsip_handle_ev_3xx,
/* E_SIP_REG_4xx */ ccsip_handle_ev_4xx,
/* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_failure_response,
/* E_SIP_REG_TMR_ACK */ ccsip_handle_ev_tmr_ack,
/* E_SIP_REG_TMR_EXPIRE */ ccsip_handle_ev_tmr_expire,
/* E_SIP_REG_TMR_WAIT */ ccsip_handle_ev_default,
/* E_SIP_REG_TMR_RETRY */ ccsip_handle_ev_tmr_retry,
/* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
},
/* SIP_REG_STATE_REGISTERED
*/
{
/* E_SIP_REG_REG_REQ */ ccsip_handle_ev_default,
/* E_SIP_REG_CANCEL */ ccsip_handle_ev_reg_cancel,
/* E_SIP_REG_1xx */ ccsip_handle_ev_default,
/* E_SIP_REG_2xx */ ccsip_handle_ev_default,
/* E_SIP_REG_3xx */ ccsip_handle_ev_default,
/* E_SIP_REG_4xx */ ccsip_handle_ev_default,
/* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_default,
/* E_SIP_REG_TMR_ACK */ ccsip_handle_ev_default,
/* E_SIP_REG_TMR_EXPIRE */ ccsip_handle_ev_tmr_expire,
/* E_SIP_REG_TMR_WAIT */ ccsip_handle_ev_default,
/* E_SIP_REG_TMR_RETRY */ ccsip_handle_ev_tmr_retry,
/* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
},
/* SIP_REG_STATE_UNREGISTERING
*/
{
/* E_SIP_REG_REG_REQ */ ccsip_handle_ev_default,
/* E_SIP_REG_CANCEL */ ccsip_handle_ev_reg_cancel,
/* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
/* E_SIP_REG_2xx */ ccsip_handle_ev_unreg_2xx,
/* E_SIP_REG_3xx */ ccsip_handle_ev_3xx,
/* E_SIP_REG_4xx */ ccsip_handle_ev_4xx,
/* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_failure_response,
/* E_SIP_REG_TMR_ACK */ ccsip_handle_ev_unreg_tmr_ack,
/* E_SIP_REG_TMR_EXPIRE */ ccsip_handle_ev_default,
/* E_SIP_REG_TMR_WAIT */ ccsip_handle_ev_standby_keepalive_tmr_expire,
/* E_SIP_REG_TMR_RETRY */ ccsip_handle_ev_tmr_retry,
/* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
},
/* SIP_REG_STATE_IN_FALLBACK
*/
{
/* E_SIP_REG_REG_REQ */ sip_regmgr_ev_default,
/* E_SIP_REG_CANCEL */ sip_regmgr_ev_cancel,
/* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
/* E_SIP_REG_2xx */ sip_regmgr_ev_in_fallback_2xx,
/* E_SIP_REG_3xx */ sip_regmgr_ev_default,
/* E_SIP_REG_4xx */ sip_regmgr_ev_fallback_retry,
/* E_SIP_REG_FAILURE_RESPONSE */ sip_regmgr_ev_fallback_retry,
/* E_SIP_REG_TMR_ACK */ sip_regmgr_ev_tmr_ack_retry,
/* E_SIP_REG_TMR_EXPIRE */ sip_regmgr_ev_default,
/* E_SIP_REG_TMR_WAIT */ sip_regmgr_ev_default,
/* E_SIP_REG_TMR_RETRY */ sip_regmgr_ev_tmr_ack_retry,
/* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
},
/* SIP_REG_STATE_STABILITY_CHECK
*/
{
/* E_SIP_REG_REG_REQ */ sip_regmgr_ev_default,
/* E_SIP_REG_CANCEL */ sip_regmgr_ev_cancel,
/* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
/* E_SIP_REG_2xx */ sip_regmgr_ev_stability_check_2xx,
/* E_SIP_REG_3xx */ sip_regmgr_ev_default,
/* E_SIP_REG_4xx */ sip_regmgr_ev_default,
/* E_SIP_REG_FAILURE_RESPONSE */ sip_regmgr_ev_default,
/* E_SIP_REG_TMR_ACK */ sip_regmgr_ev_tmr_ack_retry,
/* E_SIP_REG_TMR_EXPIRE */ sip_regmgr_ev_default,
/* E_SIP_REG_TMR_WAIT */ sip_regmgr_ev_stability_check_tmr_wait,
/* E_SIP_REG_TMR_RETRY */ sip_regmgr_ev_tmr_ack_retry,
/* E_SIP_REG_CLEANUP */ sip_regmgr_ev_default,
},
/* SIP_REG_STATE_TOKEN_WAIT
*/
{
/* E_SIP_REG_REG_REQ */ sip_regmgr_ev_default,
/* E_SIP_REG_CANCEL */ sip_regmgr_ev_default,
/* E_SIP_REG_1xx */ ccsip_handle_ev_1xx,
/* E_SIP_REG_2xx */ sip_regmgr_ev_token_wait_2xx,
/* E_SIP_REG_3xx */ sip_regmgr_ev_default,
/* E_SIP_REG_4xx */ ccsip_handle_ev_4xx,
/* E_SIP_REG_FAILURE_RESPONSE */ ccsip_handle_ev_failure_response,
/* E_SIP_REG_TMR_ACK */ sip_regmgr_ev_tmr_ack_retry,
/* E_SIP_REG_TMR_EXPIRE */ sip_regmgr_ev_default,
/* E_SIP_REG_TMR_WAIT */ sip_regmgr_ev_token_wait_tmr_wait,
/* E_SIP_REG_TMR_RETRY */ sip_regmgr_ev_tmr_ack_retry,
/* E_SIP_REG_CLEANUP */ sip_regmgr_ev_cleanup,
}
};
/*
* This function gets the supported option tags from the 200 OK response
* to the REG message sent.
*/
void
sip_get_supported_options_2xx (ccsipCCB_t *ccb, sipMessage_t *response)
{
const char *supported;
ccb->supported_tags = 0;
supported = sippmh_get_cached_header_val(response, SUPPORTED);
if (supported != NULL) {
/*
* Supported header is found, find the interrested supported
* function from 2xx response from the REG msg. sent. Note that
* the sippmh_parse_supported_require() can be used but
* decided to minimize the impact on performance parsing all other
* tags that are not interested during registration times and
* vice versa making changes to sippmh_parse_supported_require()
* to parse the tags that are not interested for other messages
* also impact the processing time for other messages.
*/
if (strcasestr(supported, REQ_SUPP_PARAM_CISCO_SRTP_FALLBACK)) {
/* cisco SRTP fallback is supported by the other end */
ccb->supported_tags |= cisco_srtp_fallback_tag;
}
}
}
/*
* This function starts the Register message
* ack timer. If no response is received from
* the register message within four minutes,
* this timer will pop and resend the Register
* message.
*/
void
sip_start_ack_timer (ccsipCCB_t *ccb)
{
uint16_t ack_timer_index;
if (ccb->index == REG_BACKUP_CCB) {
ack_timer_index = MAX_REG_LINES;
} else {
ack_timer_index = ccb->dn_line - 1;
}
CCSIP_DEBUG_REG_STATE( DEB_L_C_F_PREFIX " ccb->index=%d ack_timer_index=%d ",
DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, 0, "sip_start_ack_timer"),
ccb->index, ack_timer_index);
if (cprStartTimer(ack_tmrs[ack_timer_index], SIP_REG_TMR_ACK_TICKS,
(void *)(long)ccb->index) == CPR_FAILURE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
"sip_start_ack_timer", "cprStartTimer");
}
}
/*
* This function stops the Register message
* ack timer.
*/
void
sip_stop_ack_timer (ccsipCCB_t *ccb)
{
uint16_t ack_timer_index;
if (ccb->index == REG_BACKUP_CCB) {
ack_timer_index = MAX_REG_LINES;
} else {
ack_timer_index = ccb->dn_line - 1;
}
CCSIP_DEBUG_REG_STATE( DEB_L_C_F_PREFIX " ccb->index=%d ack_timer_index=%d ",
DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->dn_line, 0, "sip_stop_ack_timer"),
ccb->index, ack_timer_index);
if (cprCancelTimer(ack_tmrs[ack_timer_index]) == CPR_FAILURE) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
"sip_stop_ack_timer", "cprCancelTimer");
}
}
void
sip_reg_sm_change_state (ccsipCCB_t *ccb, sipRegSMStateType_t new_state)
{
if (g_disable_mass_reg_debug_print == FALSE) {
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Registration state change: %s ---> "
"%s\n", DEB_L_C_F_PREFIX_ARGS(SIP_STATE, ccb->index, ccb->dn_line, "sip_reg_sm_change_state"),
sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
sip_util_reg_state2string(new_state));
}
ccb->state = (sipSMStateType_t) new_state;
if (ccb->index == REG_CCB_START) {
if ((new_state > SIP_REG_STATE_REGISTERED) || (!refresh_reg_msg)) {
dump_reg_msg = TRUE;
} else {
dump_reg_msg = FALSE;
}
}
}
void
ccsip_handle_ev_reg_req (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
static const char fname[] = "ccsip_handle_ev_reg_req";
char line_name[MAX_LINE_NAME_SIZE];
int value;
config_get_value(CFGID_PROXY_REGISTER, &value, sizeof(value));
if (value == 0) {
ui_set_sip_registration_state(ccb->dn_line, FALSE);
CCSIP_DEBUG_REG_STATE(get_debug_string(DEBUG_REG_DISABLED),
ccb->index, ccb->dn_line, fname);
return;
}
ccsip_register_clear_all_logs();
sip_stop_ack_timer(ccb);
sip_start_ack_timer(ccb);
(void) sip_platform_register_expires_timer_stop(ccb->index);
sip_util_get_new_call_id(ccb);
ccb->authen.cred_type = 0;
ccb->retx_counter = 0;
config_get_line_string(CFGID_LINE_NAME, line_name, ccb->dn_line,
sizeof(line_name));
config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &ccb->reg.tmr_expire,
sizeof(ccb->reg.tmr_expire));
ccb->reg.act_time = (int) time(NULL);
if (sipSPISendRegister(ccb, 0, line_name, ccb->reg.tmr_expire) != TRUE) {
// set expire timer and cleanup ccb in non-ccm mode.
// do not change the expire timer value in ccm mode
if (ccb->cc_type != CC_CCM) {
ccsip_register_cleanup(ccb, TRUE);
}
log_clear(LOG_REG_MSG);
log_msg(LOG_REG_MSG);
}
sip_reg_sm_change_state(ccb, SIP_REG_STATE_REGISTERING);
}
void
ccsip_handle_ev_default (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
if ((event->type == (int) E_SIP_REG_CANCEL) && (ccb->state == (int) SIP_REG_STATE_IDLE)) {
(void) sip_platform_register_expires_timer_stop(ccb->index);
ccb->authen.cred_type = 0;
ccb->retx_counter = 0;
ccb->reg.tmr_expire = 0;
ccb->reg.act_time = 0;
ccsip_register_cleanup(ccb, FALSE);
}
/* only free SIP messages, timeouts are internal */
if (event->type < (int) E_SIP_REG_TMR_ACK) {
free_sip_message(event->u.pSipMessage);
}
}
void
ccsip_handle_ev_tmr_expire (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
// Initiate registration if prime line or not in failover state
if ((!CCM_Failover_Table.failover_started) ||
(ccb->index == REG_CCB_START)) {
/*If the phone is registered with CSPS, the failover_started flag
* will always be false. Therefore, this code will always be
* executed. */
/* Cleanup and re-initialize CCB */
sip_sm_call_cleanup(ccb);
refresh_reg_msg = TRUE;
/* send a message to the SIP_REG SM to initiate registration */
if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
} else {
ccsip_handle_ev_default(ccb, event);
}
}
void
ccsip_handle_ev_idle_tmr_expire (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
if (ccb->cc_type == CC_CCM) {
if (ccb->index == REG_BACKUP_CCB) {
ccsip_handle_ev_tmr_expire(ccb, event);
} else {
ccsip_handle_ev_default(ccb, event);
}
} else {
/* assuming CSPS */
/* Cleanup and re-initialize CCB */
sip_sm_call_cleanup(ccb);
/* send a message to the SIP_REG SM to initiate registration */
if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
}
}
void
ccsip_handle_ev_tmr_ack (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
log_clear(LOG_REG_AUTH_ACK_TMR);
log_msg(LOG_REG_AUTH_ACK_TMR);
if (ccb->cc_type == CC_CCM) {
/*
* regmgr - Send tmr ack event to the regmgr/
*/
sip_regmgr_ev_tmr_ack_retry(ccb, event);
} else {
/*
* regmgr - Assume it is csps
*/
/* Cleanup and re-initialize CCB */
sip_sm_call_cleanup(ccb);
/* send a message to the SIP_REG SM to initiate registration */
if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
}
}
void
ccsip_handle_ev_1xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
static const char fname[] = "ccsip_handle_ev_1xx";
sipMessage_t *response = NULL;
int status_code = 0;
char status[LOG_MAX_LEN];
response = event->u.pSipMessage;
if (sipGetResponseCode(response, &status_code) < 0) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_CODE),
ccb->index, ccb->dn_line, fname);
return;
}
free_sip_message(response);
switch (status_code) {
case SIP_1XX_TRYING:
CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2),
ccb->index, ccb->dn_line, fname,
sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
"SIP", status_code);
return;
default:
CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2), ccb->index,
ccb->dn_line, fname,
sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
"SIP BAD", status_code);
snprintf(status, sizeof(status), "in %d, information", status_code);
log_clear(LOG_REG_UNSUPPORTED);
log_msg(LOG_REG_UNSUPPORTED, status);
ccsip_register_cleanup(ccb, TRUE);
return;
}
}
static boolean
ccsip_get_exp_time_2xx (ccsipCCB_t *ccb, sipContact_t *contact_info,
const char *expires, uint32_t *exp_time_ret)
{
static const char fname[] = "ccsip_get_exp_time_2xx";
boolean exp_found = FALSE;
char src_addr_str[MAX_IPADDR_STR_LEN];
char user[MAX_LINE_NAME_SIZE];
int i;
uint32_t gmt_time; //TODO convert to time_t
//uint32_t diff_time; //TODO convert to time_t
int32_t gmt_rc;
uint32_t exp_time;
uint32_t register_delta;
/* did the server change the expires time? */
/*
* Form the contact header.
* The proxy can return multiple contacts so we will need to see which one
* matches this REGISTER.
*/
config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &exp_time, sizeof(uint32_t));
if (contact_info != NULL) {
ipaddr2dotted(src_addr_str, &ccb->src_addr);
config_get_line_string(CFGID_LINE_NAME, user, ccb->dn_line,
sizeof(user));
/* is expires header for this line included in the contact? */
for (i = 0; i < contact_info->num_locations; i++) {
if ((sippmh_cmpURLStrings(contact_info->locations[i]->genUrl->u.sipUrl->user,
user, FALSE) == 0) &&
(strcmp(contact_info->locations[i]->genUrl->u.sipUrl->host,
src_addr_str) == 0)) {
if ((contact_info->params[i].expires > 0) &&
(contact_info->params[i].expires < exp_time)) {
exp_time = contact_info->params[i].expires;
exp_found = TRUE;
CCSIP_DEBUG_REG_STATE(get_debug_string(DEBUG_REG_PROXY_EXPIRES),
ccb->index, ccb->dn_line, fname);
break;
}
}
}
}
if (exp_found != TRUE) {
//expires param is not found in the CONTACT header
// look for Expires header.
config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &exp_time,
sizeof(exp_time));
if (expires) {
gmt_rc = gmt_string_to_seconds((char *)expires,
(unsigned long *)&gmt_time);
if (gmt_rc != -1) {
// We only want to update the expires timeout if it is lower
// than our predefined threshold. We don't want to allow
// people to keep us hung up for infinite periods of time
if (gmt_rc == 1) {
// We got a numeric entry in the expires field
if (gmt_time < exp_time) {
exp_time = gmt_time;
exp_found = TRUE;
}
}
}
}
}
/*
* Subtract some user defined period of time to account for network delay
* or the possibility that the registration server is down and this
* request has to be processed by a backup server after the timeout
* occurs. If the user has not defined this value in the config, it
* defaults to 5 seconds.
*/
config_get_value(CFGID_TIMER_REGISTER_DELTA, &register_delta,
sizeof(register_delta));
/*
* Sanity check the register delta value as the proxy could have returned
* a much lower registration period in its' response. The minimum
* registration expiration is 60 seconds to prevent the phone from being
* flooded with msgs.
*/
if ((exp_time - register_delta) < MIN_REGISTRATION_PERIOD) {
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX
"Warning - Registration period received (%d) "
"minus configured timer_register_delta (%d) is less than "
"%d seconds.\n", DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname), exp_time,
register_delta, MIN_REGISTRATION_PERIOD);
exp_found = FALSE;
} else {
exp_time = exp_time - register_delta;
exp_found = TRUE;
}
*exp_time_ret = exp_time;
return (exp_found);
}
/*
* Function: ccsip_check_ccm_restarted
*
* Parameters:
* new_reg_ccb - pointer to ccsipCCB_t of REG CCB.
* contact_info - Pointer to sipContact_t.
*
* Description:
* The function detects CCM just came up i.e. it sees the phone
* registration as a new registration. This means CCM has restarted
* between a REG refresh cycle.
*
* Note:
* CCM only sends x-cisco-newreg to the first REG that it sees
* from the phone as a new REG. If the phone has more than one lines,
* the REG of the rest of the lines will not have the x-cisco-newreg.
*
* Returns:
* TRUE - CCM restarted is detected.
* FALSE - CCM restarted is not detected.
*/
static boolean
ccsip_check_ccm_restarted (sipContact_t *contact_info)
{
int i;
if (contact_info == NULL) {
/* No contact info. */
return (FALSE);
}
for (i = 0; i < contact_info->num_locations; i++) {
if (contact_info->params[i].flags & SIP_CONTACT_PARM_X_CISCO_NEWREG) {
/*
* CCM or proxy just indicates that it sees the REG
* as a new registration to it. This means that the CCM or
* proxy has restarted.
*/
return (TRUE);
}
}
return (FALSE);
}
/*
* Function: update_sis_protocol_version
*
* Parameters:
* response - 200 OK message pointer
*
* Description:
* The function parses theupported header in response and updates
* SIS protocol version received. If no version is received the default
* SEADRAGON version gets updated
*
* Returns:
* void
*/
void
update_sis_protocol_version (sipMessage_t *response)
{
const char *supported;
char * sipver;
supported = sippmh_get_cached_header_val(response, SUPPORTED);
if (supported != NULL) {
sipver = strcasestr(supported, REQ_SUPP_PARAM_CISCO_SISTAG);
if (sipver) {
cc_uint32_t major = SIS_PROTOCOL_MAJOR_VERSION_SEADRAGON, minor = 0, addtnl = 0;
if ( sscanf ( &sipver[strlen(REQ_SUPP_PARAM_CISCO_SISTAG)], "%d.%d.%d",
&major, &minor, &addtnl) == 3) {
platSetSISProtocolVer ( major, minor, addtnl,REQ_SUPP_PARAM_CISCO_SISTAG);
return;
}
}
}
/* All other cases we set the version to 1.0.0 */
platSetSISProtocolVer ( SIS_PROTOCOL_MAJOR_VERSION_SEADRAGON, 0, 0,REQ_SUPP_PARAM_CISCO_SISTAG);
}
void
update_cme_sis_version (sipMessage_t *response)
{
const char *supported;
char * sipver;
supported = sippmh_get_cached_header_val(response, SUPPORTED);
if (supported != NULL) {
sipver = strcasestr(supported, REQ_SUPP_PARAM_CISCO_CME_SISTAG);
if (sipver) {
cc_uint32_t major = 0, minor = 0, addtnl = 0;
if ( sscanf( &sipver[strlen(REQ_SUPP_PARAM_CISCO_CME_SISTAG)], "%d.%d.%d",
&major, &minor, &addtnl) ==3) {
platSetSISProtocolVer(major, minor, addtnl,REQ_SUPP_PARAM_CISCO_CME_SISTAG);
}
}
}
}
void
ccsip_handle_ev_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
static const char fname[] = "ccsip_handle_ev_2xx";
sipMessage_t *response = event->u.pSipMessage;
const char *pViaHeaderStr = NULL;
sipVia_t *via = NULL;
uint32_t exp_time;
//uint32_t line_feature;
int dns_err_code;
int nat_enable = 0;
int nat_rx_proc_enable = 0;
//int last_button_index =0;
const char *datehdr = NULL;
const char *contact = NULL;
const char *expires = NULL;
sipContact_t *contact_info = NULL;
//line_t line_index = 0;
//ccsipCCB_t *line_ccb = NULL;
// Extract Date header and store
datehdr = sippmh_get_header_val(response, SIP_HEADER_DATE, NULL);
if (datehdr) {
// Copy date header in a global variable since it would be needed
// to set system time
sstrncpy(ccm_date.datestring, datehdr, sizeof(ccm_date.datestring));
ccm_date.valid = TRUE;
// call ntp set time handler (TNP/cnu specific; stub for legacy)
// do not call the handler if 2xx is from StdBy CCM
// We do not need to set the time when in the browser
//if (ccb->index != REG_BACKUP_CCB) {
// SipNtpUpdateClockFromCCM();
//}
}
contact = sippmh_get_cached_header_val(response, CONTACT);
if (contact != NULL) {
/* There is a contact header pass it */
contact_info = sippmh_parse_contact(contact);
}
/* Update the sip interface protocol version */
update_sis_protocol_version(response);
/*update the CME for the version negotiation feature */
update_cme_sis_version(response);
if (ccb->dn_line == PRIMARY_LINE && ccsip_check_ccm_restarted(contact_info)) {
/* CCM has restarted detected */
CCSIP_DEBUG_MESSAGE(DEB_F_PREFIX"Detected server has restarted via line %d\n",
DEB_F_PREFIX_ARGS(SIP_CCM_RESTART, fname), ccb->dn_line);
sip_regmgr_ccm_restarted(ccb);
}
sip_stop_ack_timer(ccb);
clean_method_request_trx(ccb, sipMethodRegister, TRUE);
if (ccb->send_reason_header) {
ccb->send_reason_header = FALSE;
sipUnregisterReason[0] = '\0';
}
/*
* Get expiration time. The expriation time are from contact info. or
* from the expire header.
*/
expires = sippmh_get_header_val(response, SIP_HEADER_EXPIRES, NULL);
if (ccsip_get_exp_time_2xx(ccb, contact_info, expires, &exp_time)
== FALSE) {
/*
* The expire time received in 200OK is smaller than the minimum
* allowed. The phone will be unregistered and a message will be
* displayed under the Status Messages. The phone will retry to
* register after the configured expire-timer interval.
*/
config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &exp_time,
sizeof(uint32_t));
ccb->reg.tmr_expire = exp_time;
ccb->reg.act_time = (int) time(NULL);
sip_reg_sm_change_state(ccb, SIP_REG_STATE_UNREGISTERING);
if (ccsip_register_send_msg(SIP_REG_CANCEL, ccb->index)
!= SIP_REG_OK) {
ccsip_register_cleanup(ccb, FALSE);
}
(void) sip_platform_register_expires_timer_start(ccb->reg.tmr_expire * 1000,
ccb->index);
if (contact_info != NULL) {
sippmh_free_contact(contact_info);
}
free_sip_message(response);
log_clear(LOG_REG_EXPIRE);
log_msg(LOG_REG_EXPIRE);
return;
}
ccb->reg.registered = 1;
sip_reg_sm_change_state(ccb, SIP_REG_STATE_REGISTERED);
regall_fail_attempt = FALSE;
if (ccb->index != REG_BACKUP_CCB) {
registration_reject = FALSE;
ui_set_sip_registration_state(ccb->dn_line, TRUE);
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Setting Reg state to TRUE for line=%d\n",
DEB_F_PREFIX_ARGS(SIP_REG_STATE, fname), ccb->dn_line);
/* Get supported options from the supported header from the response */
sip_get_supported_options_2xx(ccb, response);
} else {
log_clear(LOG_REG_BACKUP);
}
if (contact_info != NULL) {
sippmh_free_contact(contact_info);
}
ccb->reg.tmr_expire = exp_time;
ccb->reg.act_time = (int) time(NULL);
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Starting expires timer (%d "
"sec)\n", DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->index, ccb->dn_line, fname),
ccb->reg.tmr_expire);
(void) sip_platform_register_expires_timer_start(ccb->reg.tmr_expire * 1000,
ccb->index);
if (ccb->cc_type == CC_CCM) {
/*
* regmgr - A 200 OK will reach here only if the state is
* REGISTERING, the unreg_200ok eve is handled
* separately.
*/
ti_config_table_t *ccm_table_ptr;
ccm_table_ptr = (ti_config_table_t *) ccb->cc_cfg_table_entry;
if ((ccm_table_ptr == CCM_Active_Standby_Table.active_ccm_entry) &&
start_standby_monitor) {
ccsipCCB_t *standby_ccb;
start_standby_monitor = FALSE;
sip_platform_set_ccm_status();
/*
* Kickoff monitoring the standby
*/
standby_ccb = sip_sm_get_ccb_by_index(REG_BACKUP_CCB);
if (CCM_Active_Standby_Table.standby_ccm_entry) {
config_get_value(CFGID_TIMER_REGISTER_EXPIRES,
&exp_time, sizeof(uint32_t));
standby_ccb->reg.tmr_expire = exp_time;
standby_ccb->reg.act_time = (int) time(NULL);
sip_reg_sm_change_state(standby_ccb,
SIP_REG_STATE_UNREGISTERING);
(void) ccsip_register_send_msg(SIP_REG_CANCEL, standby_ccb->index);
(void) sip_platform_register_expires_timer_start(standby_ccb->reg.tmr_expire * 1000,
standby_ccb->index);
}
} else if (ccm_table_ptr ==
CCM_Active_Standby_Table.standby_ccm_entry) {
/*
* REGMGR - Update stats Got a 200OK for a expires 0
* Keepalive msg to standby, update stats ?
*/
}
}
config_get_value(CFGID_NAT_ENABLE, &nat_enable, sizeof(nat_enable));
config_get_value(CFGID_NAT_RECEIVED_PROCESSING, &nat_rx_proc_enable,
sizeof(nat_rx_proc_enable));
if (nat_enable == 1 && nat_rx_proc_enable == 1) {
pViaHeaderStr = sippmh_get_cached_header_val(response, VIA);
if (pViaHeaderStr != NULL) {
via = sippmh_parse_via(pViaHeaderStr);
if (via != NULL) {
if (via->recd_host != NULL) {
cpr_ip_addr_t received_ip;
memset(&received_ip, 0, sizeof(cpr_ip_addr_t));
dns_err_code = dnsGetHostByName(via->recd_host,
&received_ip, 100, 1);
if (dns_err_code == 0) {
util_ntohl(&received_ip, &received_ip);
} else {
sip_config_get_nat_ipaddr(&received_ip);
}
if (util_compare_ip(&received_ip, &(ccb->src_addr)) == FALSE) {
/*
* The address the proxy/registration server received
* is not the same as the one that we think we have
* so we'll update our address and re-register with
* the proxy/registration server
*/
ccb->reg.rereg_pending = 1;
// Make sure our running config has the correct
// IP address that we got from the proxy server
sip_config_set_nat_ipaddr(&received_ip);
if (ccsip_register_send_msg(SIP_REG_CANCEL, ccb->index)
!= SIP_REG_OK) {
ccsip_register_cleanup(ccb, FALSE);
}
// Update the tel ccb that this reg line belongs to
ccb = sip_sm_get_ccb_by_index((line_t)(ccb->index - REG_CCB_START + 1));
if (ccb) {
ccb->src_addr = received_ip;
}
}
}
// Cleanup memory
sippmh_free_via(via);
}
}
}
free_sip_message(response);
}
void
ccsip_handle_ev_3xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
static const char fname[] = "ccsip_handle_ev_3xx";
sipMessage_t *response = NULL;
int status_code = 0;
char status[LOG_MAX_LEN];
char user[MAX_LINE_NAME_SIZE];
sipUrl_t *url;
const char *contact = NULL;
response = event->u.pSipMessage;
clean_method_request_trx(ccb, sipMethodRegister, TRUE);
if (sipGetResponseCode(response, &status_code) < 0) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_CODE),
ccb->index, ccb->dn_line, fname);
free_sip_message(response);
return;
}
switch (status_code) {
case SIP_RED_MULT_CHOICES /* 300 */:
case SIP_RED_MOVED_PERM /* 301 */:
case SIP_RED_MOVED_TEMP /* 302 */:
case SIP_RED_USE_PROXY /* 305 */:
CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2),
ccb->index, ccb->dn_line, fname,
sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
"SIP", status_code);
sip_sm_200and300_update(ccb, response, status_code);
/*
* Record the Contact header. For 3xx messages we are recording
* the Contact header here, not in the sipSPICheckResponse() header,
* so that the ACK response to 3xx is sent to the original INVITE
* destination (or to the Record-Route specified destination), rather
* than to the new 302 Contact
*/
contact = sippmh_get_cached_header_val(response, CONTACT);
if (contact) {
if (ccb->contact_info) {
sippmh_free_contact(ccb->contact_info);
}
ccb->contact_info = sippmh_parse_contact(contact);
}
/*
* Check the validity of Contact header
*/
if (!ccb->contact_info) {
CCSIP_DEBUG_ERROR("%s: Error: Invalid Contact field. Aborting "
"REGISTER.\n", fname);
free_sip_message(response);
ccsip_register_cleanup(ccb, TRUE);
return;
}
if (ccb->contact_info->locations[0]->genUrl->schema == URL_TYPE_SIP) {
url = ccb->contact_info->locations[0]->genUrl->u.sipUrl;
} else {
CCSIP_DEBUG_ERROR("%s: Error: URL is not Sip. Aborting "
"REGISTER.\n", fname);
free_sip_message(response);
ccsip_register_cleanup(ccb, TRUE);
return;
}
sstrncpy(ccb->reg.proxy, url->host, MAX_IPADDR_STR_LEN);
ccb->reg.port = url->port;
if (ccb->contact_info) {
sippmh_free_contact(ccb->contact_info);
ccb->contact_info = NULL;
}
sip_util_get_new_call_id(ccb);
/*
* Send out a new REGISTER
*/
ccb->authen.cred_type = 0;
config_get_line_string(CFGID_LINE_NAME, user, ccb->dn_line,
sizeof(user));
if (sipSPISendRegister(ccb, 0, user, ccb->reg.tmr_expire) != TRUE) {
ccsip_register_cleanup(ccb, TRUE);
free_sip_message(response);
log_clear(LOG_REG_RED_MSG);
log_msg(LOG_REG_RED_MSG);
}
return;
default:
free_sip_message(event->u.pSipMessage);
snprintf(status, sizeof(status), "in %d, redirection", status_code);
log_clear(LOG_REG_UNSUPPORTED);
log_msg(LOG_REG_UNSUPPORTED, status);
ccsip_register_cleanup(ccb, TRUE);
}
}
void
ccsip_handle_ev_4xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
static const char fname[] = "ccsip_handle_ev_4xx";
sipMessage_t *response = NULL;
int status_code = 0;
const char *authenticate = NULL;
char user[MAX_LINE_NAME_SIZE];
credentials_t credentials;
char status[LOG_MAX_LEN];
sip_authen_t *sip_authen = NULL;
char *author_str = NULL;
char uri[MAX_IPADDR_STR_LEN + 10]; /* Proxy IP address string */
char tmp_str[STATUS_LINE_MAX_LEN];
ti_config_table_t *ccm_table_ptr = NULL;
ccm_table_ptr = (ti_config_table_t *) ccb->cc_cfg_table_entry;
response = event->u.pSipMessage;
clean_method_request_trx(ccb, sipMethodRegister, TRUE);
if (sipGetResponseCode(response, &status_code) < 0) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_CODE),
ccb->index, ccb->dn_line, fname);
free_sip_message(response);
return;
}
/*
* Set reject flag if we get 4xx from publisher cucm.
* Note: if non-prime dn is congfigured with #, such as 1234##,
* then phone will get 404 for that DN, even though the prime DN is
* registered.
*/
if (ccm_table_ptr &&
ccb->index != REG_BACKUP_CCB) {
DEF_DEBUG(DEB_F_PREFIX"Receive 4xx in ccm mode. set registration_reject to TRUE.\n",
DEB_F_PREFIX_ARGS(SIP_REG, fname));
registration_reject = TRUE;
}
switch (status_code) {
case SIP_CLI_ERR_UNAUTH:
case SIP_CLI_ERR_PROXY_REQD:
CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2),
ccb->index, ccb->dn_line, fname,
sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
"SIP", status_code);
if (cred_get_credentials_r(ccb, &credentials) == FALSE) {
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"no more credentials, retry %d, %d\n",
DEB_L_C_F_PREFIX_ARGS(SIP_CRED, ccb->index, ccb->dn_line, fname),
ccb->authen.retries_401_407,
MAX_RETRIES_401);
if (ccb->cc_type == CC_CCM) {
sip_regmgr_ev_failure_response(ccb, event);
free_sip_message(response);
return;
}
ccsip_register_cleanup(ccb, TRUE);
free_sip_message(response);
log_clear(LOG_REG_AUTH_NO_CRED);
log_msg(LOG_REG_AUTH_NO_CRED);
break;
}
authenticate = sippmh_get_header_val(response, AUTH_HDR(status_code),
NULL);
if (authenticate) {
sip_authen = sippmh_parse_authenticate(authenticate);
}
if (sip_authen) {
if (sip_authen->scheme == SIP_DIGEST) {
if (authenticate != NULL) {
ccb->retx_counter = 0;
config_get_line_string(CFGID_LINE_NAME, user, ccb->dn_line,
sizeof(user));
ccb->authen.cnonce[0] = '\0';
snprintf(uri, sizeof(uri), "sip:%s", ccb->reg.proxy); /* proxy */
if (sipSPIGenerateAuthorizationResponse(sip_authen, uri,
SIP_METHOD_REGISTER,
credentials.id,
credentials.pw,
&author_str,
&(ccb->authen.nc_count),
ccb)) {
if (author_str) {
if (ccb->authen.authorization != NULL) {
cpr_free(ccb->authen.authorization);
ccb->authen.authorization = NULL;
}
ccb->authen.authorization =
(char *) cpr_malloc(strlen(author_str) *
sizeof(char) + 1);
if (ccb->authen.authorization != NULL) {
sstrncpy(ccb->authen.authorization, author_str,
strlen(author_str) * sizeof(char) + 1);
ccb->authen.status_code = status_code;
}
cpr_free(author_str);
}
} else {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
ccb->index, ccb->dn_line, fname,
"sipSPIGenerateAuthorizationResponse");
}
if (!sipSPISendRegister(ccb, TRUE, user,
ccb->reg.tmr_expire)){
ccsip_register_cleanup(ccb, TRUE);
log_clear(LOG_REG_AUTH_MSG);
log_msg(LOG_REG_AUTH_MSG);
}
} else {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
ccb->index, ccb->dn_line, fname,
"sippmh_parse_authenticate");
ccsip_register_cleanup(ccb, TRUE);
log_clear(LOG_REG_AUTH_HDR_MSG);
log_msg(LOG_REG_AUTH_HDR_MSG);
}
} else {
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"auth scheme unsupported= %d\n",
DEB_F_PREFIX_ARGS(SIP_AUTH, fname), sip_authen->scheme);
ccsip_register_cleanup(ccb, TRUE);
log_clear(LOG_REG_AUTH_SCH_MSG);
log_msg(LOG_REG_AUTH_SCH_MSG);
}
sippmh_free_authen(sip_authen);
}
free_sip_message(response);
return;
case SIP_CLI_ERR_INTERVAL_TOO_SMALL:
{
int new_expires = MAX_REG_EXPIRES;
const char *msg_ptr = NULL;
char line_name[MAX_LINE_NAME_SIZE];
msg_ptr = sippmh_get_header_val(response,
(const char *)SIP_HEADER_MIN_EXPIRES,
NULL);
if (msg_ptr) {
new_expires = strtoul(msg_ptr, NULL, 10);
}
//ensure new Min-Expires is > what we set before in Expires
if (new_expires > ccb->reg.tmr_expire) {
ccb->reg.tmr_expire = new_expires;
} else {
ccb->reg.tmr_expire = MAX_REG_EXPIRES;
}
//We have to make a fresh request
sip_stop_ack_timer(ccb);
sip_start_ack_timer(ccb);
(void) sip_platform_register_expires_timer_stop(ccb->index);
sip_util_get_new_call_id(ccb);
ccb->authen.cred_type = 0;
ccb->retx_counter = 0;
config_get_line_string(CFGID_LINE_NAME, line_name, ccb->dn_line,
sizeof(line_name));
ccb->reg.act_time = (int) time(NULL);
if (sipSPISendRegister(ccb, 0, line_name, ccb->reg.tmr_expire) != TRUE) {
// set expire timer and cleanup ccb in non-ccm mode.
// do not change the expire timer value in ccm mode
if (ccb->cc_type != CC_CCM) {
ccsip_register_cleanup(ccb, TRUE);
}
log_clear(LOG_REG_MSG);
log_msg(LOG_REG_MSG);
}
//no change in state
}
free_sip_message(response);
return;
/*
* 404 (Not Found)
* 413 (Request Entity Too Large)
* 480 (Temporarily Unavailable)
* 486 (Busy here)
*/
case SIP_CLI_ERR_NOT_FOUND:
case SIP_CLI_ERR_LARGE_MSG:
case SIP_CLI_ERR_NOT_AVAIL:
case SIP_CLI_ERR_BUSY_HERE:
if (ccb->cc_type == CC_CCM) {
if (ccb->state == (int) SIP_REG_STATE_TOKEN_WAIT) {
clean_method_request_trx(ccb, sipMethodRefer, TRUE);
sip_regmgr_ev_token_wait_4xx_n_5xx(ccb, event);
} else {
/*
* Phone sends a REGISTER message with expires=0 as a
* Keepalive msg. Proxy and CCM will respond with a
* 200 OK.
*/
if (ccb->index != REG_BACKUP_CCB) {
if (ccsip_register_get_register_state() != SIP_REG_UNREGISTERING) {
if (((ti_config_table_t *)(ccb->cc_cfg_table_entry)) ||
ccb->dn_line == PRIMARY_LINE) {
if (platGetPhraseText(STR_INDEX_REGISTRATION_REJECTED,
(char *)tmp_str, STATUS_LINE_MAX_LEN - 1)== CPR_SUCCESS) {
ui_set_notification(CC_NO_LINE, CC_NO_CALL_ID, tmp_str, 15, FALSE,
DEF_NOTIFY_PRI);
}
}
log_clear(STR_INDEX_REGISTRATION_REJECTED);
log_msg(STR_INDEX_REGISTRATION_REJECTED);
}
}
if (process_retry_after(ccb, response) == FALSE) {
sip_regmgr_ev_failure_response(ccb, event);
}
}
} else {
if (process_retry_after(ccb, response) == FALSE) {
ccsip_register_cleanup(ccb, TRUE);
}
}
free_sip_message(response);
return;
default:
if (ccb->cc_type == CC_CCM) {
if (ccb->state == (int) SIP_REG_STATE_TOKEN_WAIT) {
clean_method_request_trx(ccb, sipMethodRefer, TRUE);
sip_regmgr_ev_token_wait_4xx_n_5xx(ccb, event);
} else {
sip_regmgr_ev_failure_response(ccb, event);
}
free_sip_message(response);
return;
}
CCSIP_DEBUG_STATE(get_debug_string(DEBUG_FUNCTION_ENTRY2),
ccb->index, ccb->dn_line, fname,
sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
"SIP BAD", status_code);
snprintf(status, sizeof(status), "in %d, client error", status_code);
ccsip_register_cleanup(ccb, TRUE);
snprintf(status, sizeof(status), "in %d, request failure", status_code);
log_clear(LOG_REG_UNSUPPORTED);
log_msg(LOG_REG_UNSUPPORTED, status);
free_sip_message(response);
break;
}
if (ccb->reg.rereg_pending != 0) {
ccb->reg.rereg_pending = 0;
if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
}
}
void
ccsip_handle_ev_failure_response (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
static const char fname[] = "ccsip_handle_ev_failure_response";
sipMessage_t *response = NULL;
int status_code = 0;
char status[LOG_MAX_LEN];
sipStatusCodeClass_t code_class = codeClassInvalid;
ti_config_table_t *ccm_table_ptr = NULL;
/*
* Set reject flag if we get 5xx/6xx from publisher cucm.
*/
ccm_table_ptr = (ti_config_table_t *) ccb->cc_cfg_table_entry;
if (ccm_table_ptr &&
ccb->index != REG_BACKUP_CCB) {
registration_reject = TRUE;
DEF_DEBUG(DEB_F_PREFIX"registration has been rejected. Set registration_reject to TRUE.\n",
DEB_F_PREFIX_ARGS(SIP_REG, fname));
}
response = event->u.pSipMessage;
clean_method_request_trx(ccb, sipMethodRegister, TRUE);
if (sipGetResponseCode(response, &status_code) < 0) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_CODE),
ccb->index, ccb->dn_line, fname);
free_sip_message(response);
ccsip_register_cleanup(ccb, TRUE);
return;
}
code_class = sippmh_get_code_class((uint16_t)status_code);
log_clear(LOG_REG_AUTH);
switch (code_class) {
case codeClass5xx:
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_FAILURE),
ccb->index, ccb->dn_line, fname, status_code);
log_msg(LOG_REG_AUTH_SERVER_ERR, status_code);
break;
case codeClass6xx:
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_FAILURE),
ccb->index, ccb->dn_line, fname, status_code);
log_msg(LOG_REG_AUTH_GLOBAL_ERR, status_code);
break;
default:
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_REG_SIP_RESP_FAILURE),
ccb->index, ccb->dn_line, fname, status_code);
snprintf(status, sizeof(status), "in %d, ??? error", status_code);
log_msg(LOG_REG_AUTH_UNKN_ERR, status_code);
break;
}
if (ccb->cc_type == CC_CCM) {
if (ccb->state == (int) SIP_REG_STATE_TOKEN_WAIT) {
/* Handle only 503 error condition for other errors
* use default state
*/
if (status_code == SIP_SERV_ERR_UNAVAIL) {
clean_method_request_trx(ccb, sipMethodRefer, TRUE);
sip_regmgr_ev_token_wait_4xx_n_5xx(ccb, event);
free_sip_message(response);
} else {
sip_regmgr_ev_default(ccb, event);
}
return;
}
/* retry registration using value in the Retry-After header
* if response code is 503 with Retry-After
*/
if ((status_code == SIP_SERV_ERR_UNAVAIL) &&
(process_retry_after(ccb, response) == TRUE)) {
free_sip_message(response);
return;
}
/*
* regmgr - Pass the event to the regmgr
*/
sip_regmgr_ev_failure_response(ccb, event);
free_sip_message(response);
} else {
/*
* Assume CSPS for now
*/
switch (status_code) {
/*
* 500 (Server Internal Error)
* 503 (Service Unavailable)
* 600 (Busy),
* 603 (Declined
*/
case SIP_SERV_ERR_INTERNAL:
case SIP_SERV_ERR_UNAVAIL:
case SIP_FAIL_BUSY:
case SIP_FAIL_DECLINE:
if (process_retry_after(ccb, response) == FALSE) {
ccsip_register_cleanup(ccb, TRUE);
}
free_sip_message(response);
return;
default:
break;
}
ccsip_register_cleanup(ccb, TRUE);
free_sip_message(response);
if (ccb->reg.rereg_pending != 0) {
ccb->reg.rereg_pending = 0;
if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index)
!= SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
}
}
}
/*
* ccsip_handle_ev_tmr_retry()
*
* This function is called when registration re-try timer
* pops or an ICMP unreachable is received after sending
* out the registration. The ICMP unreachable code sets the
* retx_counter to MAX to force the code to try the next
* proxy in the list. Event.u.usrInfo is set to the IP
* address that bounced or -1 if is a timeout.
*/
void
ccsip_handle_ev_tmr_retry (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
static const char fname[] = "ccsip_handle_ev_tmr_retry";
boolean start_timer;
uint32_t value;
int dns_err_code = DNS_ERR_HOST_UNAVAIL;
cpr_ip_addr_t ip_addr;
CPR_IP_ADDR_INIT(ip_addr);
start_timer = (ccsip_register_get_register_state() == SIP_REG_UNREGISTERING) ?
(FALSE) : (TRUE);
config_get_value(CFGID_SIP_RETX, &value, sizeof(value));
if (value > MAX_NON_INVITE_RETRY_ATTEMPTS) {
value = MAX_NON_INVITE_RETRY_ATTEMPTS;
}
if (ccb->retx_counter >= value) {
if (ccb->cc_type == CC_CCM /* RAMC Some other state */) {
/*
* regmgr - Send event to the regmgr
*/
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Reached here for ccb->index=%d \n",
DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname), ccb->index);
sip_regmgr_ev_tmr_ack_retry(ccb, event);
return;
} else {
/*
* Assume CSPS for now
*/
ccb->retx_counter = 0;
/*
* Did the registration msg bounce trying to reach the outbound
* proxy (1st check) or did it timeout trying to reach the
* outbound proxy (2nd check)?
*/
util_ntohl(&ip_addr, &(event->u.UsrInfo));
if (util_compare_ip(&ip_addr, &(ccb->outBoundProxyAddr)) ||
((event->u.UsrInfo.type == CPR_IP_ADDR_INVALID) &&
util_check_if_ip_valid(&(ccb->outBoundProxyAddr)))) {
/*
* If there are more records, reset address to force code
* to use next entry. If not then bail.
*/
ccb->outBoundProxyPort = 0;
dns_err_code = DNS_OK;
/*
* Trouble reaching the normal proxy. Get another proxy
* if records are available
*/
} else if (str2ip(ccb->reg.proxy, &ccb->reg.addr) != 0) {
dns_err_code = sipTransportGetServerAddrPort(ccb->reg.proxy,
&ccb->reg.addr,
(uint16_t *) &ccb->reg.port,
&ccb->SRVhandle,
TRUE);
if (dns_err_code == 0) {
util_ntohl(&(ccb->reg.addr), &(ccb->reg.addr));
} else {
ccb->reg.addr = ip_addr_invalid;
}
/*
* Modify destination fields in call back timer struct
*/
(void) sip_platform_msg_timer_update_destination(ccb->index,
&(ccb->reg.addr),
ccb->reg.port);
} else {
/* No other proxy to try */
dns_err_code = DNS_ERR_HOST_UNAVAIL;
}
/*
* Cleanup if unable to find another proxy
*/
if (dns_err_code != DNS_OK) {
/*
* All retransmit attempts have been exhausted.
* Cleanup the call and move to the IDLE state
*/
ccsip_register_cleanup(ccb, start_timer);
log_clear(LOG_REG_RETRY);
log_msg(LOG_REG_RETRY);
if ((ccb->index == REG_BACKUP_CCB) &&
(ccb->cc_type != CC_CCM)) {
log_clear(LOG_REG_BACKUP);
log_msg(LOG_REG_BACKUP);
}
if (ccb->reg.rereg_pending != 0) {
ccb->reg.rereg_pending = 0;
if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index)
!= SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
}
return;
}
}
}
if (ccb->state != (int) SIP_REG_STATE_REGISTERED) {
/*
* Handling Retry timer in REGISTERED state is not needed
* the event has come due to race condition
*/
ccb->retx_counter++;
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"Resending message: #%d\n",
DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname), ccb->retx_counter);
if (sipSPISendLastMessage(ccb) != TRUE) {
if (ccb->cc_type == CC_CCM) {
sip_regmgr_ev_tmr_ack_retry(ccb, event);
} else {
ccsip_register_cleanup(ccb, start_timer);
}
return;
}
ccsip_register_retry_timer_start(ccb);
}
}
void
ccsip_handle_ev_reg_cancel (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
char user[MAX_LINE_NAME_SIZE];
int exp_time = 0;
ccsip_register_clear_all_logs();
sip_stop_ack_timer(ccb);
sip_start_ack_timer(ccb);
(void) sip_platform_register_expires_timer_stop(ccb->index);
sip_util_get_new_call_id(ccb);
ccb->authen.cred_type = 0;
ccb->retx_counter = 0;
ccb->reg.tmr_expire = 0;
ccb->reg.act_time = 0;
config_get_line_string(CFGID_LINE_NAME, user, ccb->dn_line, sizeof(user));
if (sipSPISendRegister(ccb, 0, user, exp_time) != TRUE) {
log_clear(LOG_REG_CANCEL_MSG);
log_msg(LOG_REG_CANCEL_MSG);
} else if ((ccb->index == REG_BACKUP_CCB) && (ccb->cc_type != CC_CCM)) {
log_clear(LOG_REG_BACKUP);
log_msg(LOG_REG_BACKUP);
}
sip_reg_sm_change_state(ccb, SIP_REG_STATE_UNREGISTERING);
}
void
ccsip_handle_ev_unreg_2xx (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
static const char fname[] = "ccsip_handle_ev_unreg_2xx";
sipMessage_t *response = event->u.pSipMessage;
int timeout;
free_sip_message(response);
ccb->reg.registered = 0;
ccb->reg.tmr_expire = 0;
ccb->reg.act_time = 0;
clean_method_request_trx(ccb, sipMethodRegister, TRUE);
if (ccb->cc_type == CC_CCM) {
if (ccb->index == REG_BACKUP_CCB) {
/*
* Stay in unregistering state and wait for the
* expires timer to pop to send the next keepalive.
*/
sip_stop_ack_timer(ccb);
if (new_standby_available) {
sip_regmgr_replace_standby(ccb);
}
timeout = sip_config_get_keepalive_expires();
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Keep alive timer (%d sec)\n",
DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->index, ccb->dn_line, fname), timeout);
(void) sip_platform_standby_keepalive_timer_start(timeout * 1000);
} else {
sip_reg_sm_change_state(ccb, SIP_REG_STATE_IDLE);
sip_stop_ack_timer(ccb);
if (ccsip_register_all_unregistered() == TRUE) {
ccsip_register_set_register_state(SIP_REG_IDLE);
/*
* regmgr - FALLBACK: Pick the ccb of the ccm that has
* come up (falling back) and post the fallback event,
* now that the unregistering is done.
* Will commit change after integration with ccm.
*/
}
platSetSISProtocolVer(1,0,0,NULL);
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"set[1] the SIS protocol ver to 1.0.0\n",
DEB_F_PREFIX_ARGS(SIP_REG, fname));
}
} else {
sip_reg_sm_change_state(ccb, SIP_REG_STATE_IDLE);
sip_stop_ack_timer(ccb);
if (ccsip_register_all_unregistered() == TRUE) {
ccsip_register_set_register_state(SIP_REG_IDLE);
}
/*
* Our unregistration from the proxy has succeeded now we
* can reregister again
*/
if (ccb->reg.rereg_pending != 0) {
ccb->reg.rereg_pending = 0;
if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index)
!= SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
}
platSetSISProtocolVer(1,0,0,NULL);
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"set[2] the SIS protocol ver to 1.0.0\n",
DEB_F_PREFIX_ARGS(SIP_REG, fname));
}
}
void
ccsip_handle_ev_unreg_tmr_ack (ccsipCCB_t *ccb, sipSMEvent_t *event)
{
log_clear(LOG_REG_AUTH_UNREG_TMR);
log_msg(LOG_REG_AUTH_UNREG_TMR);
if (ccb->cc_type == CC_CCM) {
/*
* regmgr - Send tmr ack event to the regmgr
*/
sip_regmgr_ev_tmr_ack_retry(ccb, event);
return;
}
ccsip_register_cleanup(ccb, FALSE);
/*
* We are unregistering ourselves from the proxy when our own registration
* timer has expired. This means that we do not need to complete our
* unregistration from the proxy since it is being done automatically.
* We can just send our new registration now
*/
if (ccb->reg.rereg_pending != 0) {
ccb->reg.rereg_pending = 0;
if (ccsip_register_send_msg(SIP_REG_REQ, ccb->index) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
}
}
void
ccsip_handle_ev_standby_keepalive_tmr_expire (ccsipCCB_t *ccb,
sipSMEvent_t *event)
{
/*
* regmgr - If there is a fallback ccb in TOKEN_WAIT
* state waiting to fallback notify it so it can
* continue with the fallback procedure.
*/
if (ccb->cc_type == CC_CCM) {
/*
* REGMGR - CHECK if this event gets called.
* Will get in here only for REG_BACKUP_CCB in
* unregistering state i.e, the standby cc which
* is periodically monitored.
*/
/*
* Stay in unregistering state and post a message
* to send another keep-alive message.
*/
(void) sip_platform_standby_keepalive_timer_stop();
(void) ccsip_register_send_msg(SIP_REG_CANCEL, ccb->index);
} else {
ccsip_handle_ev_default(ccb, event);
}
}
int
sip_reg_sm_process_event (sipSMEvent_t *pEvent)
{
static const char fname[] = "sip_reg_sm_process_event";
ccsipCCB_t *ccb = NULL;
ccb = pEvent->ccb;
if (!ccb) {
CCSIP_DEBUG_ERROR("%s: Error: ccb is null. Unable to process event "
"<%d>\n", fname, pEvent->type);
return (-1);
}
/* Unbind UDP ICMP response handler */
if ((REG_CHECK_EVENT_SANITY((int) ccb->state, (int) pEvent->type)) &&
(REG_EVENT_ACTION(ccb->state, (int) pEvent->type))) {
if (dump_reg_msg == TRUE) {
DEF_DEBUG(DEB_L_C_F_PREFIX"%s <- %s\n",
DEB_L_C_F_PREFIX_ARGS(SIP_REG_STATE, ccb->dn_line, ccb->index, fname),
sip_util_reg_state2string((sipRegSMStateType_t)ccb->state),
sip_util_reg_event2string((sipRegSMEventType_t)pEvent->type));
}
REG_EVENT_ACTION(ccb->state, pEvent->type) (ccb, pEvent);
} else {
/* Invalid State/Event pair */
CCSIP_DEBUG_ERROR("%s: Error: illegal state/event pair: (%d <-- %d)\n",
fname, ccb->state, pEvent->type);
return (-1);
}
return (0);
}
const char *
sip_util_reg_event2string (sipRegSMEventType_t event)
{
switch (event) {
case E_SIP_REG_REG_REQ:
return ("E_SIP_REG_REG_REQ");
case E_SIP_REG_CANCEL:
return ("E_SIP_REG_CANCEL");
case E_SIP_REG_1xx:
return ("E_SIP_REG_1xx");
case E_SIP_REG_2xx:
return ("E_SIP_REG_2xx");
case E_SIP_REG_3xx:
return ("E_SIP_REG_3xx");
case E_SIP_REG_4xx:
return ("E_SIP_REG_4xx");
case E_SIP_REG_FAILURE_RESPONSE:
return ("E_SIP_REG_FAILURE_RESPONSE");
case E_SIP_REG_TMR_EXPIRE:
return ("E_SIP_REG_TMR_EXPIRE");
case E_SIP_REG_TMR_ACK:
return ("E_SIP_REG_TMR_ACK");
case E_SIP_REG_TMR_WAIT:
return ("E_SIP_REG_TMR_WAIT");
case E_SIP_REG_TMR_RETRY:
return ("E_SIP_REG_TMR_RETRY");
case E_SIP_REG_CLEANUP:
return ("E_SIP_REG_CLEANUP");
default:
return ("SIP_REG_STATE_UNKNOWN");
}
}
char *
sip_util_reg_state2string (sipRegSMStateType_t state)
{
switch (state) {
case SIP_REG_STATE_NONE:
return ("SIP_REG_STATE_NONE");
case SIP_REG_STATE_IDLE:
return ("SIP_REG_STATE_IDLE");
case SIP_REG_STATE_REGISTERING:
return ("SIP_REG_STATE_REGISTERING");
case SIP_REG_STATE_REGISTERED:
return ("SIP_REG_STATE_REGISTERED");
case SIP_REG_STATE_UNREGISTERING:
return ("SIP_REG_STATE_UNREGISTERING");
case SIP_REG_STATE_IN_FALLBACK:
return ("SIP_REG_STATE_IN_FALLBACK");
case SIP_REG_STATE_STABILITY_CHECK:
return ("SIP_REG_STATE_STABILITY_CHECK");
case SIP_REG_STATE_TOKEN_WAIT:
return ("SIP_REG_STATE_TOKEN_WAIT");
default:
return ("SIP_REG_STATE_UNKNOWN");
}
}
sipRegSMEventType_t
ccsip_register_sip2sipreg_event (int sip_event)
{
static const char fname[] = "ccsip_register_sip2sipreg";
sipRegSMEventType_t reg_event = E_SIP_REG_NONE;
switch (sip_event) {
case E_SIP_1xx:
reg_event = E_SIP_REG_1xx;
break;
case E_SIP_2xx:
reg_event = E_SIP_REG_2xx;
break;
case E_SIP_3xx:
reg_event = E_SIP_REG_3xx;
break;
case E_SIP_FAILURE_RESPONSE:
reg_event = E_SIP_REG_4xx;
break;
default:
CCSIP_DEBUG_ERROR("%s: Error: Unknown event.\n", fname);
reg_event = E_SIP_REG_NONE;
break;
}
return (reg_event);
}
void
ccsip_register_timeout_retry (void *data)
{
static const char fname[] = "ccsip_register_timeout_retry";
ccsipCCB_t *ccb;
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
ccb = (ccsipCCB_t *) data;
if (ccb == NULL) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_GENERAL_FUNCTIONCALL_FAILED),
fname, "ccsip_register_timeout_retry");
return;
}
if (ccsip_register_send_msg(SIP_TMR_REG_RETRY, ccb->index) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
}
/*
* timer callback function
*
* The function will search for the line that set the timer and then
* (1) send expire event to sm or
* (2) set another 60s timer. The setting of another timer is necessary
* because the max ticks for an OS timer is 10m. The expire timer can
* be larger. Therefore, set x 1m timers and count down.
*/
int
ccsip_register_send_msg (uint32_t cmd, line_t ndx)
{
static const char fname[] = "ccsip_register_send_msg";
ccsip_registration_msg_t *register_msg;
ccsipCCB_t *ccb = NULL;
CCM_ID ccm_id = UNUSED_PARAM;
ti_config_table_t * cc_cfg_table;
/*
* Get the ccm_id type from ccb corresponding to ndx.
* Currently, only SIP_TMR_REG_RETRY msg in SIPTaskProcessListEvent is
* making use of ccm_id field. No other reg msg make use of ccm_id. Also in
* case of SIP_REG_UPDATE, ccm_id will not be determined below but remain
* initialized to UNUSED_PARAM because, in case of SIP_REG_UPDATE, ndx is
* not ccb->index but number of available lines when lkem is attached.
*/
if (cmd != SIP_REG_UPDATE) {
ccb = sip_sm_get_ccb_by_index(ndx);
if (ccb != NULL) {
cc_cfg_table = (ti_config_table_t *)(ccb->cc_cfg_table_entry);
if (cc_cfg_table != NULL) {
ccm_id = cc_cfg_table->ti_specific.ti_ccm.ccm_id;
}
else {
CCSIP_DEBUG_ERROR("%s: Error: cc_cfg_table is null.\n", fname);
return SIP_ERROR;
}
}
else {
CCSIP_DEBUG_ERROR("%s: Error: ccb is null.\n", fname);
return SIP_ERROR;
}
}
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"cmd=%d=%s ccb->index=%d ccm_id=%s\n",
DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname),
cmd, REG_CMD_PRINT(cmd), ndx, CCM_ID_PRINT(ccm_id));
register_msg = (ccsip_registration_msg_t *)
SIPTaskGetBuffer(sizeof(ccsip_registration_msg_t));
if (!register_msg) {
CCSIP_DEBUG_ERROR("%s: Error: get buffer failed.\n", fname);
return SIP_ERROR;
}
register_msg->ccb_index = ndx;
register_msg->ccm_id = ccm_id;
if (SIPTaskSendMsg(cmd, register_msg, sizeof(ccsip_registration_msg_t), NULL)
== CPR_FAILURE) {
cpr_free(register_msg);
CCSIP_DEBUG_ERROR("%s: Error: send buffer failed.\n", fname);
return SIP_ERROR;
}
return SIP_REG_OK;
}
void
ccsip_register_retry_timer_start (ccsipCCB_t *ccb)
{
static const char fname[] = "ccsip_register_retry_timer_start";
int timeout;
int time_t1;
int time_t2;
/* Double the timeout value and do exponential time increases
* The doubling is used because the invite timeout is too short
*/
config_get_value(CFGID_TIMER_T1, &time_t1, sizeof(time_t1));
timeout = time_t1 * (1 << ccb->retx_counter);
config_get_value(CFGID_TIMER_T2, &time_t2, sizeof(time_t2));
if (timeout > time_t2) {
timeout = time_t2;
}
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Starting reTx timer (%d msec)\n",
DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->index, ccb->dn_line, fname), timeout);
ccb->retx_flag = TRUE;
if (sip_platform_msg_timer_start(timeout, (void *)ccb, ccb->index,
sipPlatformUISMTimers[ccb->index].message_buffer,
sipPlatformUISMTimers[ccb->index].message_buffer_len,
sipMethodRegister,
&(sipPlatformUISMTimers[ccb->index].ipaddr),
sipPlatformUISMTimers[ccb->index].port,
TRUE) != SIP_OK) {
CCSIP_DEBUG_ERROR(get_debug_string(DEBUG_SIP_FUNCTIONCALL_FAILED),
ccb->index, ccb->dn_line, fname,
"sip_platform_msg_timer_start");
ccb->retx_flag = FALSE;
}
}
void
ccsip_register_cleanup (ccsipCCB_t *ccb, boolean start)
{
static const char fname[] = "ccsip_register_cleanup";
int exp_time;
config_get_value(CFGID_TIMER_REGISTER_EXPIRES, &exp_time, sizeof(exp_time));
ccb->reg.registered = 0;
if (ccb->index != REG_BACKUP_CCB) {
ui_set_sip_registration_state(ccb->dn_line, FALSE);
}
sip_stop_ack_timer(ccb);
if ((start) && (ccb->state != (int) SIP_REG_STATE_UNREGISTERING)) {
if (ccb->index == REG_BACKUP_CCB) {
ccb->reg.tmr_expire = (exp_time > 5) ? exp_time - 5 : exp_time;
} else {
ccb->reg.tmr_expire = 60;
}
ccb->reg.act_time = (int) time(NULL);
CCSIP_DEBUG_STATE(DEB_L_C_F_PREFIX"Starting expires timer (%d "
"sec)\n", DEB_L_C_F_PREFIX_ARGS(SIP_TIMER, ccb->index, ccb->dn_line, fname),
ccb->reg.tmr_expire);
(void) sip_platform_register_expires_timer_start(ccb->reg.tmr_expire * 1000,
ccb->index);
}
sip_reg_sm_change_state(ccb, SIP_REG_STATE_IDLE);
if (ccsip_register_all_unregistered() == TRUE) {
ccsip_register_set_register_state(SIP_REG_IDLE);
}
/*
* Always check how sip_sm_call_cleanup is implemented.
* The function has a tendency to change.
*/
/* Cleanup and re-initialize CCB */
sip_sm_call_cleanup(ccb);
}
cc_int32_t
ccsip_register_cmd (cc_int32_t argc, const char *argv[])
{
/*
* On 7970 phones the command is reg line [option] [line]
* On 7940/60 the command is reg [option] [line]
* Thus the location in the argument array is different
* based on the phone type. OFFSET is used to get around
* this difference while still having common code.
*/
#define OFFSET 1
ccsipCCB_t *ccb = NULL;
line_t ndx = 0;
line_t temp_line = 0;
char str_val[MAX_LINE_NAME_SIZE];
const char *line_string;
char *strtol_end;
/*
* check if need help
*/
if ((argc == 2 + OFFSET) && (argv[1 + OFFSET][0] == '?')) {
debugif_printf("reg [option] [line]\n");
debugif_printf(" options = 0: unregister\n");
debugif_printf(" 1: register\n");
debugif_printf(" line = 1 through 6\n");
debugif_printf(" = backup (line 1 to backup proxy)\n");
debugif_printf("\n");
return (0);
}else if (cpr_strcasecmp(argv[0 + OFFSET], "line") == 0) {
/*
make sure the user entered a complete command
*/
if (argc < 3 + OFFSET) {
debugif_printf("Incomplete command\n");
debugif_printf("reg [option] [line]\n");
debugif_printf(" options = 0: unregister\n");
debugif_printf(" 1: register\n");
debugif_printf(" line = 1 through 6\n");
debugif_printf(" = backup (line 1 to backup proxy)\n");
debugif_printf("\n");
return (0);
}
/* make sure we have at least one line configured */
config_get_line_string(CFGID_LINE_NAME, str_val, 1, sizeof(str_val));
if ((strcmp(str_val, UNPROVISIONED) == 0) || (str_val[0] == '\0')) {
debugif_printf("Error:No lines configured\n");
return (0);
}
line_string = argv[2 + OFFSET];
if (cpr_strcasecmp(line_string, "backup") == 0) {
temp_line = REG_BACKUP_LINE;
} else {
errno = 0;
temp_line = (line_t) strtol(line_string, &strtol_end, 10);
if (errno || line_string == strtol_end || !sip_config_check_line(temp_line)) {
debugif_printf("Error:Invalid Line\n");
return (0);
}
}
ndx = SIP_REG_REGLINE2LINE(temp_line - 1);
ccb = sip_sm_get_ccb_by_index(ndx);
if (ccb == NULL) {
debugif_printf("Unable to retrieve registration information for this line.\n");
debugif_printf("Command aborted.\n");
return (0);
}
if ((temp_line == REG_BACKUP_LINE) && util_check_if_ip_valid(&(ccb->dest_sip_addr)) == FALSE) {
debugif_printf("Backup Proxy is invalid or not configured.\n");
return (0);
}
switch (argv[1 + OFFSET][0]) {
case '0':
if (ccb->index != REG_BACKUP_CCB) {
ui_set_sip_registration_state(ccb->dn_line, FALSE);
}
if (temp_line != REG_BACKUP_LINE) {
debugif_printf("Unregistering line %d\n", temp_line);
} else {
debugif_printf("Unregistering line 1 to backup proxy\n");
}
(void) sip_platform_register_expires_timer_stop(ccb->index);
sip_stop_ack_timer(ccb);
if (ccsip_register_send_msg(SIP_REG_CANCEL, ndx) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, FALSE);
}
break;
case '1':
/* Cleanup and re-initialize CCB */
sip_sm_call_cleanup(ccb);
if (temp_line != REG_BACKUP_LINE) {
debugif_printf("Registering line %d\n", temp_line);
} else {
debugif_printf("Registering line 1 to backup proxy\n");
}
(void) ccsip_register_send_msg(SIP_REG_REQ, ndx);
break;
default:
debugif_printf("Invalid Option Value - please choose 1 or 0\n");
return (0);
}
}
return (0);
}
/*
* Function: build_reg_flags
*
* Parameters:
*
* Description: builds a 3 character string representing various flags
* for use by the show_reg command
*
* Returns: none
*
*/
static void
build_reg_flags (char *buf, int buf_size, int prox_reg, ccsipCCB_t *ccb,
boolean provisioned)
{
sstrncpy(buf, "...", buf_size);
if (!provisioned || !prox_reg) {
return;
}
buf[1] = '1'; // Set the Provisioned bit
if (ccb->authen.authorization != NULL) {
buf[0] = '1';
} else {
if (ccb->authen.status_code != 0) {
buf[0] = 'x';
}
}
if (ccb->reg.registered) {
buf[2] = '1';
} else {
buf[2] = 'x';
}
}
/*
* Function: show_register_data
*
* Parameters:
*
* Description: Internal print routine for show_register_cmd. Also
* called by reg command
*
* Returns:
*
*/
#define TMP_BUF_SIZE 8
static void
show_register_data (void)
{
ccsipCCB_t *ccb;
char buf[TMP_BUF_SIZE];
line_t ndx = 0;
int proxy_register = 0;
boolean valid_line = FALSE;
int timer_count_down = 0;
config_get_value(CFGID_PROXY_REGISTER, &proxy_register,
sizeof(proxy_register));
debugif_printf("\nLINE REGISTRATION TABLE\nProxy Registration: ");
if (proxy_register == 1) {
debugif_printf("ENABLED");
} else {
debugif_printf("DISABLED");
}
debugif_printf(", state: %s\n",
ccsip_register_state_name(ccsip_register_get_register_state()));
debugif_printf("line APR state timer expires proxy:port\n");
debugif_printf("---- --- ------------- ---------- ---------- ----------------------------\n");
for (ndx = REG_CCB_START; ndx <= REG_BACKUP_CCB; ndx++) {
ccb = sip_sm_get_ccb_by_index(ndx);
valid_line = FALSE;
if (ndx == REG_BACKUP_CCB) {
valid_line = TRUE;
} else {
if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
valid_line = TRUE;
}
}
// calc the time until registration expires
if (ccb && valid_line) {
if (!proxy_register || !valid_line) {
timer_count_down = 0;
} else {
if (ccb->reg.act_time == 0) {
timer_count_down = 0;
} else if ((sipRegSMStateType_t)ccb->state ==
SIP_REG_STATE_REGISTERING) {
timer_count_down =
(SIP_REG_TMR_ACK_TICKS / 1000) -
(((int) time(NULL)) - ccb->reg.act_time);
} else {
timer_count_down = ccb->reg.tmr_expire -
(((int) time(NULL)) - ccb->reg.act_time);
}
}
/*
* Ensure that the timer_count_down value is valid. There
* are cases where the phone completes registration before an
* SNTP/NTP response is received which makes the act_time and
* time(NULL) values inconsistent.
*/
if ((timer_count_down < 0) ||
(timer_count_down > ccb->reg.tmr_expire)) {
timer_count_down = 0;
}
}
// build the flag string
if (ccb) {
build_reg_flags((char *)&buf, TMP_BUF_SIZE, proxy_register,
ccb, valid_line);
}
if (ndx != REG_BACKUP_CCB) {
debugif_printf("%-4d", ndx - TEL_CCB_END);
} else {
debugif_printf("1-BU");
}
if (ccb && valid_line) {
debugif_printf(" %-3s %-13s %-10d %-10d %s:%d\n",
buf,
ccsip_register_reg_state_name((sipRegSMStateType_t)ccb->state),
ccb->reg.tmr_expire,
timer_count_down,
((ccb->reg.proxy[0] != '\0') ? (ccb->reg.proxy) : ("undefined")),
ccb->reg.port);
} else {
debugif_printf(" %-3s %-13s %-10d %-10d %s:%d\n",
buf, "NONE", 0, 0, "undefined", 0);
}
}
debugif_printf("\nNote: APR is Authenticated, Provisioned, Registered\n");
}
/*
* Function: show_register_cmd
*
* Parameters: argc,argv
*
* Description: Shows the current registration table
*
* Returns:
*
*/
cc_int32_t
show_register_cmd (cc_int32_t argc, const char *argv[])
{
/*
* check if need help
*/
if ((argc == 2) && (argv[1][0] == '?')) {
debugif_printf("sh reg\n");
return (0);
}
show_register_data();
return (0);
}
void
ccsip_register_clear_all_logs (void)
{
log_clear(LOG_REG_MSG);
log_clear(LOG_REG_AUTH);
log_clear(LOG_REG_RETRY);
log_clear(LOG_REG_UNSUPPORTED);
}
void
ccsip_register_reset_proxy (void)
{
ccsipCCB_t *ccb;
line_t ndx;
line_t line_end;
/*
* If this is a restart (phone is resetting) then reset the proxy
* string for each line. The proxy string is used to determine
* what address to use when registering. The proxy remains the
* same throughout a boot cycle and on restarts there is a new
* boot cycle so the proxy address is reset.
*/
line_end = 1;
/*
* REG CCBs start after the TEL CCBs.
* EG., TEL CCBs are at 1 and 2 and REG CCBs are at 3 and 4.
* So, line_end equals the number of lines and then add the TEL_CCB_END
* to get the ending of the REG CCBs
*/
line_end += TEL_CCB_END;
//ccsip_register_lines = line_end - REG_CCB_START + 1;
for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
ccb = sip_sm_get_ccb_by_index(ndx);
if (ccb) {
ccb->reg.proxy[0] = '\0';
}
}
}
//reset backup proxy registration;
ccb = sip_sm_get_ccb_by_index(REG_BACKUP_CCB);
if (ccb) {
ccb->reg.proxy[0] = '\0';
}
}
int
ccsip_register_init (void)
{
static const char fname[] = "ccsip_register_init";
static const char sipAckTimerName[] = "sipAck";
int i;
ccsip_register_set_register_state(SIP_REG_IDLE);
/*
* Create acknowledgement timers
*/
for (i = 0; i < MAX_REG_LINES + 1; i++) {
ack_tmrs[i] = cprCreateTimer(sipAckTimerName, SIP_ACK_TIMER,
TIMER_EXPIRATION, sip_msgq);
if (ack_tmrs[i] == NULL) {
CCSIP_DEBUG_ERROR("%s: timer NOT created: %d\n",
fname, i);
return SIP_ERROR;
}
}
// Initialize date holder structure
ccm_date.valid = FALSE;
ccm_date.datestring[0] = '\0';
start_standby_monitor = TRUE;
return SIP_OK;
}
ccsip_register_states_t
ccsip_register_get_register_state (void)
{
return (ccsip_register_state);
}
void
ccsip_register_set_register_state (ccsip_register_states_t state)
{
ccsip_register_state = state;
}
void
ccsip_register_cancel (boolean cancel_reg, boolean backup_proxy)
{
static const char fname[] = "ccsip_register_cancel";
ccsipCCB_t *ccb;
line_t ndx;
line_t line_end;
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
if (ccsip_register_get_register_state() == SIP_REG_IDLE) {
return;
}
ccsip_register_set_register_state(SIP_REG_UNREGISTERING);
line_end = 1;
ui_set_sip_registration_state((line_t) (line_end + 1), FALSE);
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"unregistering %d lines\n", DEB_F_PREFIX_ARGS(SIP_REG, fname), line_end);
/*
* REG CCBs start after the TEL CCBs.
* EG., TEL CCBs are at 1 and 2 and REG CCBs are at 3 and 4.
* So, line_end equals the number of lines and then add the TEL_CCB_END
* to get the ending of the REG CCBs
*/
line_end += TEL_CCB_END;
for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
if (sip_config_check_line((line_t) (ndx - TEL_CCB_END))) {
ccb = sip_sm_get_ccb_by_index(ndx);
if (!ccb) {
continue;
}
ui_set_sip_registration_state(ccb->dn_line, FALSE);
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"cancelling timers, line= %d\n",
DEB_F_PREFIX_ARGS(SIP_TIMER, fname), ccb->index);
(void) sip_platform_register_expires_timer_stop(ccb->index);
sip_stop_ack_timer(ccb);
if (cancel_reg) {
if (ccb->index == REG_CCB_START) {
ccb->send_reason_header = TRUE;
}
if (ccb->index == REG_CCB_START) {
ccb->send_reason_header = TRUE;
}
if (ccsip_register_send_msg(SIP_REG_CANCEL, ndx)
!= SIP_REG_OK) {
ccsip_register_cleanup(ccb, FALSE);
}
} else {
/* Cleanup and re-initialize CCB */
sip_sm_call_cleanup(ccb);
if (ndx == line_end) {
ccsip_register_set_register_state(SIP_REG_IDLE);
}
}
}
}
if (backup_proxy == FALSE) {
return;
}
/* cancel backup registration as well */
ccb = sip_sm_get_ccb_by_index(REG_BACKUP_CCB);
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"cancelling timers, line= %d\n",
DEB_F_PREFIX_ARGS(SIP_TIMER, fname), ccb->index);
(void) sip_platform_register_expires_timer_stop(ccb->index);
sip_stop_ack_timer(ccb);
if (cancel_reg) {
if (ccsip_register_send_msg(SIP_REG_CANCEL, REG_BACKUP_CCB)
!= SIP_REG_OK) {
ccsip_register_cleanup(ccb, FALSE);
}
} else {
/* Cleanup and re-initialize CCB */
sip_sm_call_cleanup(ccb);
}
}
void
ccsip_register_all_lines (void)
{
static const char fname[] = "ccsip_register_all_lines";
ccsipCCB_t *ccb = 0;
line_t ndx;
line_t line;
line_t line_end = 1;
int value = 0;
char proxyaddress[MAX_IPADDR_STR_LEN];
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
/* Do not register if
* - no need to register
* - and already registered
*/
line_end = 1;
config_get_value(CFGID_PROXY_REGISTER, &value, sizeof(value));
if (value == 0) {
CCSIP_DEBUG_REG_STATE(get_debug_string(DEBUG_REG_DISABLED), NULL,
NULL, fname);
// mark all unregistered
for (line = 1; line <= line_end; line++) {
if (sip_config_check_line(line)) {
ui_set_sip_registration_state(line, FALSE);
}
}
ccsip_register_reset_proxy();
return;
} else if (ccsip_register_get_register_state() == SIP_REG_REGISTERED) {
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"lines already registered\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
return;
}
ccsip_register_reset_proxy();
ccsip_register_set_register_state(SIP_REG_REGISTERING);
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"registering %d line%c\n",
DEB_F_PREFIX_ARGS(SIP_REG, fname), line_end, line_end > 1 ? 's' : ' ');
/* register line 1 to the backup proxy.
* Start with the backup as DNS lookups hold
* the task meaning it could take a while to
* register the six regular lines.
*/
ndx = REG_BACKUP_CCB;
ccb = sip_sm_get_ccb_by_index(ndx);
/* Cleanup and re-initialize CCB */
sip_sm_call_cleanup(ccb);
if (ccb->cc_type == CC_CCM) {
/*
* regmgr - Set the Backup (standby ccm) info.
*/
ti_config_table_t *standby_ccm =
CCM_Active_Standby_Table.standby_ccm_entry;
if (standby_ccm) {
ti_ccm_t *ti_ccm = &standby_ccm->ti_specific.ti_ccm;
sip_regmgr_setup_new_standby_ccb(ti_ccm->ccm_id);
} else {
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"ERROR: Standby ccm entry is NULL\n",
DEB_F_PREFIX_ARGS(SIP_REG, fname));
}
} else {
/*
* Assume CSPS since only those two for now.
*/
if (util_check_if_ip_valid(&(ccb->dest_sip_addr))) {
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"%d, 0x%x\n",
DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname),
ndx, ccb);
ccb->reg.addr = ccb->dest_sip_addr;
ccb->reg.port = (uint16_t) ccb->dest_sip_port;
if (ccb->index == REG_CCB_START) {
ccb->send_reason_header = TRUE;
} else {
ccb->send_reason_header = FALSE;
}
if (ccsip_register_send_msg(SIP_REG_REQ, ndx) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
} else {
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"%d: Backup Proxy not configured\n",
DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname), ndx);
}
}
/*
* REG CCBs start after the TEL CCBs.
* EG., TEL CCBs are at 1 and 2 and REG CCBs are at 3 and 4.
* So, line_end equals the number of lines and then add the TEL_CCB_END to
* get the ending of the REG CCBs
*/
line_end += TEL_CCB_END;
DEF_DEBUG(DEB_F_PREFIX"Disabling mass reg state", DEB_F_PREFIX_ARGS(SIP_REG, fname));
for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
ccb = sip_sm_get_ccb_by_index(ndx);
if (!ccb) {
continue;
}
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"%d, 0x%x\n",
DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname),
ndx, ccb);
/*
* Clean up and re-initialize the proxy address.
* It is possible that the REGISTER can be redirected
* and this address needs to be reused for later register attempts.
* But, on restarts and re-enabling of registering we reset back
* to the original configured proxy
*/
if (ndx == REG_CCB_START || ndx == (line_end)) {
g_disable_mass_reg_debug_print = FALSE;
} else {
g_disable_mass_reg_debug_print = TRUE;
}
sip_sm_call_cleanup(ccb);
/*
* Look up the name of the proxy
*/
sipTransportGetPrimServerAddress(ccb->dn_line, proxyaddress);
sstrncpy(ccb->reg.proxy, proxyaddress, MAX_IPADDR_STR_LEN);
ccb->reg.addr = ccb->dest_sip_addr;
ccb->reg.port = (uint16_t) ccb->dest_sip_port;
if (ccb->index == REG_CCB_START) {
ccb->send_reason_header = TRUE;
} else {
ccb->send_reason_header = FALSE;
}
ui_set_sip_registration_state(ccb->dn_line, FALSE);
if (ccsip_register_send_msg(SIP_REG_REQ, ndx) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
}
}
g_disable_mass_reg_debug_print = FALSE;
sip_platform_cc_mode_notify();
}
boolean
ccsip_register_all_registered (void)
{
ccsipCCB_t *ccb;
line_t ndx;
line_t line_end;
line_end = 1;
/*
* REG CCBs start after the TEL CCBs.
* EG., TEL CCBs are at 1 and 2 and REG CCBs are at 3 and 4.
* So, line_end equals the number of lines and then add the TEL_CCB_END
* to get the ending of the REG CCBs
*/
line_end += TEL_CCB_END;
for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
ccb = sip_sm_get_ccb_by_index(ndx);
if (ccb && (ccb->reg.registered == 0)) {
return (FALSE);
}
}
}
return (TRUE);
}
boolean
ccsip_register_all_unregistered (void)
{
ccsipCCB_t *ccb;
line_t ndx;
line_t line_end;
line_end = 1;
/*
* REG CCBs start after the TEL CCBs.
* EG., TEL CCBs are at 0 and 1 and REG CCBs are at 6 and 7.
* So, line_end equals the number of lines and then add the TEL_CCB_END
* to get the ending of the REG CCBs
*/
line_end += TEL_CCB_END;
for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
if (sip_config_check_line((line_t)(ndx - TEL_CCB_END))) {
ccb = sip_sm_get_ccb_by_index(ndx);
if (ccb && (ccb->reg.registered == 1)) {
return (FALSE);
}
}
}
return (TRUE);
}
void
ccsip_register_commit (void)
{
static const char fname[] = "ccsip_register_commit";
int register_get;
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
/*
* Determine if lines need to register or unregister
*
* register if
* - proxy_register was changed from 0 to 1
*
* unregister if
* - proxy_register was changed from 1 to 0 and already registered
*/
config_get_value(CFGID_PROXY_REGISTER, &register_get,
sizeof(register_get));
switch (register_get) {
case 0:
if (ccsip_register_get_register_state() != SIP_REG_IDLE) {
ccsip_register_cancel(TRUE, TRUE);
} else {
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"lines already unregistered.\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
}
break;
case 1:
if (ccsip_register_get_register_state() != SIP_REG_REGISTERED) {
ccsip_register_cancel(FALSE, TRUE);
ccsip_register_all_lines();
} else {
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"lines already registered.\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
}
break;
default:
CCSIP_DEBUG_ERROR(DEB_F_PREFIX"Error: invalid register_get= %d\n", DEB_F_PREFIX_ARGS(SIP_REG, fname),
register_get);
}
}
void
ccsip_backup_register_commit (void)
{
static const char fname[] = "ccsip_backup_register_commit";
line_t ndx;
ccsipCCB_t *ccb = 0;
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"\n", DEB_F_PREFIX_ARGS(SIP_REG, fname));
ndx = REG_BACKUP_CCB;
ccb = sip_sm_get_ccb_by_index(ndx);
/* cancel an existing registration if it exists */
if (util_check_if_ip_valid(&(ccb->reg.addr))) {
CCSIP_DEBUG_REG_STATE(DEB_F_PREFIX"cancelling registration, line= %d\n",
DEB_F_PREFIX_ARGS(SIP_REG, fname), ccb->index);
if (ccsip_register_send_msg(SIP_REG_CANCEL, ndx) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, FALSE);
}
}
/* Cleanup and re-initialize CCB */
sip_sm_call_cleanup(ccb);
if (util_check_if_ip_valid(&(ccb->dest_sip_addr))) {
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"%d, 0x%x\n",
DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname),
ndx, ccb);
ccb->reg.addr = ccb->dest_sip_addr;
ccb->reg.port = (uint16_t) ccb->dest_sip_port;
if (ccsip_register_send_msg(SIP_REG_REQ, ndx) != SIP_REG_OK) {
ccsip_register_cleanup(ccb, TRUE);
}
} else {
log_clear(LOG_REG_BACKUP);
}
}
void
cred_get_line_credentials (line_t line, credentials_t *pcredentials,
int id_len, int pw_len)
{
config_get_line_string(CFGID_LINE_AUTHNAME, pcredentials->id, line,
id_len);
if ((strcmp(pcredentials->id, "") == 0) ||
(strcmp(pcredentials->id, UNPROVISIONED) == 0)) {
config_get_line_string((CFGID_LINE_AUTHNAME), pcredentials->id, 1,
id_len);
}
config_get_line_string(CFGID_LINE_PASSWORD, pcredentials->pw, line,
pw_len);
if ((strcmp(pcredentials->pw, "") == 0) ||
(strcmp(pcredentials->pw, UNPROVISIONED) == 0)) {
config_get_line_string(CFGID_LINE_PASSWORD, pcredentials->pw, 1,
pw_len);
}
}
boolean
cred_get_credentials_r (ccsipCCB_t *ccb, credentials_t *pcredentials)
{
if (!(ccb->authen.cred_type & CRED_LINE) ||
(ccb->authen.retries_401_407 < MAX_RETRIES_401)) {
ccb->authen.cred_type |= CRED_LINE;
ccb->authen.retries_401_407++;
cred_get_line_credentials(ccb->dn_line, pcredentials,
sizeof(pcredentials->id),
sizeof(pcredentials->pw));
return (TRUE);
}
return (FALSE);
}
const char *
ccsip_register_state_name (ccsip_register_states_t state)
{
if ((state < SIP_REG_IDLE) || (state >= SIP_REG_NO_REGISTER)) {
return ("UNDEFINED");
}
return (ccsip_register_state_names[state]);
}
const char *
ccsip_register_reg_state_name (sipRegSMStateType_t state)
{
if ((state < SIP_REG_STATE_NONE) || (state >= SIP_REG_STATE_UNREGISTERING)) {
return ("UNDEFINED");
}
return (ccsip_register_reg_state_names[state]);
}
void
ccsip_register_shutdown ()
{
int i;
for (i = 0; i < MAX_REG_LINES + 1; i++) {
(void) cprCancelTimer(ack_tmrs[i]);
(void) cprDestroyTimer(ack_tmrs[i]);
ack_tmrs[i] = NULL;
}
}
boolean
ccsip_get_ccm_date (char *date_value)
{
if (date_value) {
if (ccm_date.valid) {
sstrncpy(date_value, ccm_date.datestring,
sizeof(ccm_date.datestring));
return (TRUE);
} else {
date_value[0] = '\0';
}
}
return (FALSE);
}
/*
* Function: ccsip_is_line_registered
*
* Parameters:
* dn_line - line number.
*
* Description: The function determines whether the current line
* is registered or not.
*
* Returns:
* TRUE if the line is registered.
* FALSE if the line is not registered or the given line is invalid.
*
*/
boolean
ccsip_is_line_registered (line_t dn_line)
{
line_t ndx;
line_t line_end;
ccsipCCB_t *ccb;
/* Get the number of lines configured */
line_end = 1;
/*
* REG CCBs start after the TEL CCBs.
* So, line_end equals the number of lines and then add the TEL_CCB_END
* to get the ending of the REG CCBs
*/
line_end += TEL_CCB_END;
for (ndx = REG_CCB_START; ndx <= line_end; ndx++) {
ccb = sip_sm_get_ccb_by_index(ndx);
if ((ccb != NULL) && (ccb->dn_line == dn_line)) {
/* found the requested REG ccb */
if (ccb->state == (int) SIP_REG_STATE_REGISTERED) {
return (TRUE);
} else {
/* the line is not in registered state */
break;
}
}
}
/* Found no matching REG ccb or the line is not in registered state */
return (FALSE);
}
/*
* Function: process_retry_after
*
* Parameters:
* ccsipCCB_t *ccb - The reg ccb.
* sipMessage_t *response - The received response.
*
* Description: The function processes the Retry-After header that may
* be present in the response.
*
* Returns:
* TRUE if a valid Retry-After header was present and processed correctly.
* FALSE if a valid Retry-After header was not present and therefore
* was not processed.
*
*/
boolean
process_retry_after (ccsipCCB_t *ccb, sipMessage_t *response)
{
const char *msg_ptr = NULL;
int32_t retry_after = 0;
static const char fname[] = "process_retry_after";
msg_ptr = sippmh_get_header_val(response,
(const char *)SIP_HEADER_RETRY_AFTER,
NULL);
if (msg_ptr) {
retry_after = strtoul(msg_ptr, NULL, 10);
} else {
return (FALSE);
}
if (retry_after > 0) {
sip_stop_ack_timer(ccb);
(void) sip_platform_register_expires_timer_start(retry_after * 1000,
ccb->index);
CCSIP_DEBUG_REG_STATE(DEB_L_C_F_PREFIX"Retrying after %d\n",
DEB_L_C_F_PREFIX_ARGS(SIP_REG, ccb->index, ccb->dn_line, fname), retry_after);
return (TRUE);
} else {
CCSIP_DEBUG_ERROR("REG %d/%d: %-35s: Error: invalid Retry-After "
"header in response.\n",
ccb->index, ccb->dn_line, fname);
return (FALSE);
}
}