mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-02-07 12:17:35 +00:00
708 lines
17 KiB
C
Executable File
708 lines
17 KiB
C
Executable File
/* 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 "cpr_types.h"
|
|
#include "cpr_stdlib.h"
|
|
#include "cpr_stdio.h"
|
|
#include "phntask.h"
|
|
#include "fsm.h"
|
|
#include "fim.h"
|
|
#include "lsm.h"
|
|
#include "sm.h"
|
|
#include "gsm.h"
|
|
#include "ccapi.h"
|
|
#include "phone_debug.h"
|
|
#include "debug.h"
|
|
#include "text_strings.h"
|
|
#include "sip_interface_regmgr.h"
|
|
#include "resource_manager.h"
|
|
#include "singly_link_list.h"
|
|
#include "platform_api.h"
|
|
|
|
#define CAC_FAILURE_TIMEOUT 5
|
|
cc_int32_t g_cacDebug = 0;
|
|
|
|
/* CAC key */
|
|
typedef struct {
|
|
callid_t call_id;
|
|
} cac_key_t;
|
|
|
|
|
|
typedef enum {
|
|
FSM_CAC_IDLE = 0,
|
|
FSM_CAC_REQ_PENDING = 1,
|
|
FSM_CAC_REQ_RESP = 2
|
|
} fsm_cac_state_e;
|
|
|
|
/* CAC structure to hold the data
|
|
*/
|
|
typedef struct cac_data_t {
|
|
void *msg_ptr;
|
|
callid_t call_id;
|
|
void *cac_fail_timer;
|
|
fsm_cac_state_e cac_state;
|
|
uint32_t sessions;
|
|
} cac_data_t;
|
|
|
|
static sll_handle_t s_cac_list = NULL;
|
|
|
|
|
|
|
|
/*
|
|
* Function responsible for searching the list waiting for
|
|
* bandwidth allocation.
|
|
*
|
|
* @param cac_data_t *key_p - pointer to the key.
|
|
* @param cac_data_t *cac_data - cac data.
|
|
*
|
|
* @return void
|
|
*
|
|
*/
|
|
static sll_match_e
|
|
fsm_cac_match_call_id (cac_data_t *key_p, cac_data_t *cac_data)
|
|
{
|
|
if (cac_data->call_id == key_p->call_id) {
|
|
|
|
return SLL_MATCH_FOUND;
|
|
}
|
|
|
|
return SLL_MATCH_NOT_FOUND;
|
|
|
|
}
|
|
|
|
/*
|
|
* Function responsible to create new data information
|
|
* for cac.
|
|
*
|
|
* @param none.
|
|
*
|
|
* @return cac_data_t *
|
|
*
|
|
*/
|
|
static cac_data_t *
|
|
fsm_get_new_cac_data (void)
|
|
{
|
|
static const char *fname="fsm_get_new_cac_data";
|
|
cac_data_t *cac_mem;
|
|
|
|
cac_mem = (cac_data_t *) cpr_malloc(sizeof(cac_data_t));
|
|
|
|
if (cac_mem == NULL) {
|
|
CAC_ERROR(CAC_F_PREFIX"No memory for CAC data.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname));
|
|
return (NULL);
|
|
}
|
|
|
|
memset(cac_mem, 0, sizeof(cac_data_t));
|
|
return (cac_mem);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Release all cac related data. This includes timer, cac_data
|
|
* and message buffers
|
|
*
|
|
* @param cac_data cac data structure
|
|
*
|
|
* @return none.
|
|
*
|
|
* @pre (cac_data not_eq NULL)
|
|
*/
|
|
|
|
static void
|
|
fsm_clear_cac_data (cac_data_t *cac_data)
|
|
{
|
|
|
|
if (cac_data->cac_fail_timer) {
|
|
(void) cprCancelTimer(cac_data->cac_fail_timer);
|
|
|
|
(void) cprDestroyTimer(cac_data->cac_fail_timer);
|
|
}
|
|
|
|
(void) sll_remove(s_cac_list, cac_data);
|
|
|
|
fim_free_event(cac_data->msg_ptr);
|
|
|
|
/* Release buffer too */
|
|
cpr_free(cac_data->msg_ptr);
|
|
|
|
cpr_free(cac_data);
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Notifies the SIP stack and UI that CAC has failed.
|
|
*
|
|
* @param cac_data cac data structure
|
|
*
|
|
* @return none.
|
|
*
|
|
* @pre (cac_data not_eq NULL)
|
|
*/
|
|
|
|
static void fsm_cac_notify_failure (cac_data_t *cac_data)
|
|
{
|
|
const char fname[] = "fsm_cac_notify_failure";
|
|
cc_setup_t *msg = (cc_setup_t *) cac_data->msg_ptr;
|
|
cc_msgs_t msg_id = msg->msg_id;
|
|
callid_t call_id = msg->call_id;
|
|
line_t line = msg->line;
|
|
int event_id = msg_id;
|
|
cc_srcs_t src_id = msg->src_id;
|
|
|
|
/* Notify UI about the failure */
|
|
lsm_ui_display_notify_str_index(STR_INDEX_NO_BAND_WIDTH);
|
|
|
|
/* Send response from network side regarding the failure */
|
|
if (event_id == CC_MSG_SETUP &&
|
|
src_id == CC_SRC_SIP) {
|
|
DEF_DEBUG(DEB_F_PREFIX"Send CAC failure to SIP %d.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname), cac_data->call_id);
|
|
cc_int_release(CC_SRC_GSM, CC_SRC_SIP, call_id, line,
|
|
CC_CAUSE_CONGESTION, NULL, NULL);
|
|
} else {
|
|
/* If the cac failed, GSM is not spinning yet, so just send the
|
|
* information to UI in this case. Other case, where GSM receives event
|
|
* will send the information from GSM.
|
|
* If the UI is not cleaned up, session infomation is not cleared.
|
|
*/
|
|
ui_call_state(evOnHook, line, call_id, CC_CAUSE_CONGESTION);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Initialize the cac timer. This timer is responsible for cleanup if the
|
|
* cac response is not received from lower layer.
|
|
*
|
|
* @param cac_data cac data structure
|
|
* timeout specify the time out in sec
|
|
*
|
|
* @return true if the timer is created scuccessfully.
|
|
* false if the timer is not created.
|
|
*
|
|
* @pre (cac_data not_eq NULL)
|
|
*/
|
|
|
|
static boolean
|
|
fsm_init_cac_failure_timer(cac_data_t *cac_data, uint32_t timeout)
|
|
{
|
|
const char fname[] = "fsm_init_cac_failure_timer";
|
|
|
|
CAC_DEBUG(DEB_F_PREFIX"cac_data call_id=%x\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname),
|
|
cac_data->call_id);
|
|
|
|
cac_data->cac_fail_timer =
|
|
cprCreateTimer("CAC failure timer", GSM_CAC_FAILURE_TIMER, TIMER_EXPIRATION,
|
|
gsm_msg_queue);
|
|
|
|
if (cac_data->cac_fail_timer == NULL) {
|
|
CAC_ERROR(CAC_F_PREFIX"CAC Timer allocation failed.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname));
|
|
return(FALSE);
|
|
}
|
|
|
|
(void) cprStartTimer(cac_data->cac_fail_timer, timeout * 1000,
|
|
(void *)(long)cac_data->call_id);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Serches through cac link list and returns cac_data
|
|
* based on call_id. This search is a singly link list search.
|
|
*
|
|
* @param call_id call_id of the call
|
|
*
|
|
* @return cac_data if found in the list
|
|
* NULL if there is no cac_data
|
|
*
|
|
* @pre (call_id not_eq CC_NO_CALL_ID)
|
|
*/
|
|
|
|
static cac_data_t *
|
|
fsm_cac_get_data_by_call_id (callid_t call_id)
|
|
{
|
|
const char fname[] = "fsm_cac_get_data_by_call_id";
|
|
cac_data_t *cac_data;
|
|
|
|
cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
|
|
|
|
while (cac_data != NULL) {
|
|
|
|
if (cac_data->call_id == call_id) {
|
|
CAC_DEBUG(DEB_F_PREFIX"cac_data found call_id=%x\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname),
|
|
cac_data->call_id);
|
|
return(cac_data);
|
|
}
|
|
|
|
cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
|
|
|
|
}
|
|
|
|
CAC_DEBUG(DEB_F_PREFIX"cac_data NOT found.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname));
|
|
return(NULL);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Initialize cac module by enabling debugs and creating a cac list.
|
|
*
|
|
* @param void
|
|
*
|
|
* @return void
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
void fsm_cac_init (void)
|
|
{
|
|
const char fname[] = "fsm_cac_init";
|
|
|
|
|
|
/* allocate and initialize cac list */
|
|
s_cac_list = sll_create((sll_match_e(*)(void *, void *))
|
|
fsm_cac_match_call_id);
|
|
|
|
if (s_cac_list == NULL) {
|
|
CAC_ERROR(CAC_F_PREFIX"CAC list creation failed.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname));
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* clears all the entries in the cac list
|
|
*
|
|
* @param void
|
|
*
|
|
* @return void
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
void fsm_cac_clear_list (void)
|
|
{
|
|
const char fname[] = "fsm_cac_clear_list";
|
|
cac_data_t *cac_data;
|
|
cac_data_t *prev_cac_data;
|
|
|
|
DEF_DEBUG(DEB_F_PREFIX"Clear all pending CAC dat.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname));
|
|
|
|
cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
|
|
|
|
while (cac_data != NULL) {
|
|
|
|
prev_cac_data = cac_data;
|
|
cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
|
|
|
|
fsm_cac_notify_failure(prev_cac_data);
|
|
fsm_clear_cac_data(prev_cac_data);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Shutdown cac module, clears all the pending cac requests
|
|
*
|
|
* @param void
|
|
*
|
|
* @return void
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
void fsm_cac_shutdown (void)
|
|
{
|
|
|
|
fsm_cac_clear_list();
|
|
|
|
sll_destroy(s_cac_list);
|
|
|
|
s_cac_list = NULL;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Check if there are pending CAC requests
|
|
*
|
|
* @param none
|
|
*
|
|
* @return cac_data returns first pending request.
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
static cac_data_t *
|
|
fsm_cac_check_if_pending_req (void)
|
|
{
|
|
cac_data_t *cac_data;
|
|
|
|
cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
|
|
|
|
while (cac_data != NULL) {
|
|
|
|
if (cac_data->cac_state == FSM_CAC_REQ_PENDING ||
|
|
cac_data->cac_state == FSM_CAC_IDLE) {
|
|
|
|
return(cac_data);
|
|
}
|
|
|
|
cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
|
|
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Check if there are pending CAC requests
|
|
*
|
|
* @param none
|
|
*
|
|
* @return cac_data returns first pending request.
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
static cc_causes_t
|
|
fsm_cac_process_bw_allocation (cac_data_t *cac_data)
|
|
{
|
|
const char fname[] = "fsm_cac_process_bw_allocation";
|
|
|
|
if (lsm_allocate_call_bandwidth(cac_data->call_id, cac_data->sessions) ==
|
|
CC_CAUSE_CONGESTION) {
|
|
|
|
DEF_DEBUG(DEB_F_PREFIX"CAC Allocation failed.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname));
|
|
|
|
fsm_cac_notify_failure(cac_data);
|
|
|
|
fsm_clear_cac_data(cac_data);
|
|
|
|
return(CC_CAUSE_CONGESTION);
|
|
}
|
|
|
|
cac_data->cac_state = FSM_CAC_REQ_PENDING;
|
|
|
|
return(CC_CAUSE_OK);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Check if there are pending CAC requests
|
|
*
|
|
* @param call_id request a cac for this call_id
|
|
* sessions number of sessions in the request
|
|
* msg ccapi msg, that is held to process
|
|
* till cac response is received.
|
|
*
|
|
* @return CC_CAUSE_BW_OK if the bandwidth is received.
|
|
* CC_CAUSE_Ok Call returned successfully, not sure about BW yet
|
|
* CC_CAUSE_ERROR: Call returned with failure.
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
cc_causes_t
|
|
fsm_cac_call_bandwidth_req (callid_t call_id, uint32_t sessions,
|
|
void *msg)
|
|
{
|
|
const char fname[] = "fsm_cac_call_bandwidth_req";
|
|
cac_data_t *cac_data, *cac_pend_data;
|
|
|
|
/* If wlan not connected return OK */
|
|
cac_data = fsm_get_new_cac_data();
|
|
|
|
if (cac_data == NULL) {
|
|
|
|
return(CC_CAUSE_CONGESTION);
|
|
}
|
|
|
|
cac_data->msg_ptr = msg;
|
|
cac_data->call_id = call_id;
|
|
cac_data->cac_state = FSM_CAC_IDLE;
|
|
cac_data->sessions = sessions;
|
|
|
|
fsm_init_cac_failure_timer(cac_data, CAC_FAILURE_TIMEOUT);
|
|
|
|
/* Make sure there is no pending requests before submitting
|
|
* another one
|
|
*/
|
|
if ((cac_pend_data = fsm_cac_check_if_pending_req()) == NULL) {
|
|
|
|
/*
|
|
* Make sure sufficient bandwidth available to make a outgoing call. This
|
|
* should be done before allocating other resources.
|
|
*/
|
|
DEF_DEBUG(DEB_F_PREFIX"CAC request for %d sessions %d.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname), call_id, sessions);
|
|
|
|
if (fsm_cac_process_bw_allocation(cac_data) == CC_CAUSE_CONGESTION) {
|
|
|
|
return(CC_CAUSE_CONGESTION);
|
|
}
|
|
|
|
cac_data->cac_state = FSM_CAC_REQ_PENDING;
|
|
|
|
} else if (cac_pend_data->cac_state == FSM_CAC_IDLE) {
|
|
|
|
if (fsm_cac_process_bw_allocation(cac_pend_data) ==
|
|
CC_CAUSE_CONGESTION) {
|
|
|
|
/* Clear all remaining data */
|
|
fsm_cac_clear_list();
|
|
|
|
return(CC_CAUSE_CONGESTION);
|
|
}
|
|
|
|
}
|
|
|
|
(void) sll_append(s_cac_list, cac_data);
|
|
|
|
return(CC_CAUSE_OK);
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
* This is called by gsm to cleanup the cac data. If there are any
|
|
* pending CAC requests and far end cancels the call, the pending
|
|
* request has to be canceled.
|
|
*
|
|
* @param call_id - call_id of the request
|
|
*
|
|
* @return none.
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
void fsm_cac_call_release_cleanup (callid_t call_id)
|
|
{
|
|
cac_data_t *cac_data;
|
|
|
|
cac_data = fsm_cac_get_data_by_call_id(call_id);
|
|
|
|
if (cac_data) {
|
|
|
|
sll_remove(s_cac_list, cac_data);
|
|
|
|
fsm_clear_cac_data(cac_data);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* Called when the bandwidth response with available bw is received. This
|
|
* also process held ccapi messages through fim event chain
|
|
*
|
|
* @param none
|
|
*
|
|
* @return CC_CAUSE_NO_RESOURCE No bandwidth
|
|
* CC_CAUSE_OK if ok
|
|
*
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
|
|
cc_causes_t
|
|
fsm_cac_process_bw_avail_resp (void)
|
|
{
|
|
const char fname[] = "fsm_cac_process_bw_avail_resp";
|
|
cac_data_t *cac_data = NULL;
|
|
cac_data_t *next_cac_data = NULL;
|
|
|
|
|
|
cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
|
|
|
|
if (cac_data != NULL) {
|
|
|
|
switch (cac_data->cac_state) {
|
|
default:
|
|
case FSM_CAC_IDLE:
|
|
DEF_DEBUG(DEB_F_PREFIX"No Pending CAC request.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname));
|
|
/*
|
|
* Make sure sufficient bandwidth available to make a outgoing call. This
|
|
* should be done before allocating other resources.
|
|
*/
|
|
if (fsm_cac_process_bw_allocation(cac_data) == CC_CAUSE_CONGESTION) {
|
|
|
|
sll_remove(s_cac_list, cac_data);
|
|
|
|
return(CC_CAUSE_NO_RESOURCE);
|
|
}
|
|
|
|
|
|
break;
|
|
case FSM_CAC_REQ_PENDING:
|
|
|
|
next_cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
|
|
sll_remove(s_cac_list, cac_data);
|
|
|
|
/* Request for the next bandwidth */
|
|
DEF_DEBUG(DEB_F_PREFIX"Process pending responses %d.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname), cac_data->call_id);
|
|
|
|
/* Let GSM process completed request */
|
|
fim_process_event(cac_data->msg_ptr, TRUE);
|
|
|
|
fsm_clear_cac_data(cac_data);
|
|
|
|
if (next_cac_data != NULL) {
|
|
/*
|
|
* Make sure sufficient bandwidth available to make a outgoing call. This
|
|
* should be done before allocating other resources.
|
|
*/
|
|
DEF_DEBUG(DEB_F_PREFIX"Requesting next allocation %d.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname), next_cac_data->call_id);
|
|
|
|
if (fsm_cac_process_bw_allocation(next_cac_data) ==
|
|
CC_CAUSE_CONGESTION) {
|
|
|
|
/* If the next data was in idle state and the request fialed
|
|
* then clean up the remaining list
|
|
*/
|
|
if (next_cac_data->cac_state == FSM_CAC_IDLE) {
|
|
/* Clear all remaining data */
|
|
fsm_cac_clear_list();
|
|
} else {
|
|
|
|
sll_remove(s_cac_list, next_cac_data);
|
|
}
|
|
|
|
return(CC_CAUSE_NO_RESOURCE);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return(CC_CAUSE_NO_RESOURCE);
|
|
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Called when the bandwidth response with failed bw is received. This
|
|
* also process held ccapi messages through fim event chain
|
|
*
|
|
* @param none
|
|
*
|
|
* @return CC_CAUSE_NO_RESOURCE No bandwidth
|
|
* CC_CAUSE_OK if ok
|
|
*
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
cc_causes_t
|
|
fsm_cac_process_bw_failed_resp (void)
|
|
{
|
|
const char fname[] = "fsm_cac_process_bw_avail_resp";
|
|
cac_data_t *cac_data = NULL;
|
|
cac_data_t *next_cac_data = NULL;
|
|
|
|
|
|
cac_data = (cac_data_t *) sll_next(s_cac_list, NULL);
|
|
|
|
if (cac_data != NULL) {
|
|
|
|
switch (cac_data->cac_state) {
|
|
default:
|
|
case FSM_CAC_IDLE:
|
|
DEF_DEBUG(DEB_F_PREFIX"No Pending request.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname));
|
|
/*
|
|
* Make sure sufficient bandwidth available to make a outgoing call. This
|
|
* should be done before allocating other resources.
|
|
*/
|
|
if (fsm_cac_process_bw_allocation(cac_data) == CC_CAUSE_CONGESTION) {
|
|
|
|
sll_remove(s_cac_list, cac_data);
|
|
|
|
return(CC_CAUSE_NO_RESOURCE);
|
|
}
|
|
|
|
break;
|
|
case FSM_CAC_REQ_PENDING:
|
|
|
|
next_cac_data = (cac_data_t *) sll_next(s_cac_list, cac_data);
|
|
|
|
sll_remove(s_cac_list, cac_data);
|
|
|
|
/* Request for the next bandwidth */
|
|
DEF_DEBUG(DEB_F_PREFIX"Process pending responses even after failure.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname));
|
|
|
|
/* Let GSM process completed request */
|
|
fsm_cac_notify_failure(cac_data);
|
|
|
|
fsm_clear_cac_data(cac_data);
|
|
|
|
if (next_cac_data != NULL) {
|
|
|
|
/*
|
|
* Make sure sufficient bandwidth available to make a outgoing call. This
|
|
* should be done before allocating other resources.
|
|
*/
|
|
if (fsm_cac_process_bw_allocation(next_cac_data) == CC_CAUSE_CONGESTION) {
|
|
|
|
/* If the next data was in idle state and the request fialed
|
|
* then clean up the remaining list
|
|
*/
|
|
if (next_cac_data->cac_state == FSM_CAC_IDLE) {
|
|
/* Clear all remaining data */
|
|
fsm_cac_clear_list();
|
|
} else {
|
|
|
|
sll_remove(s_cac_list, next_cac_data);
|
|
}
|
|
|
|
return(CC_CAUSE_NO_RESOURCE);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
return(CC_CAUSE_NO_RESOURCE);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* Process time-out event. This cause cac data to send failure notifications.
|
|
*
|
|
* @param void *tmr_data - timer data
|
|
*
|
|
* @return none
|
|
*
|
|
*
|
|
* @pre (NULL)
|
|
*/
|
|
void
|
|
fsm_cac_process_bw_fail_timer (void *tmr_data)
|
|
{
|
|
const char fname[] = "fsm_cac_process_bw_fail_timer";
|
|
|
|
DEF_DEBUG(DEB_F_PREFIX"CAC request timedout %d.\n",
|
|
DEB_F_PREFIX_ARGS("CAC", fname), (callid_t)(long)tmr_data);
|
|
|
|
/* Time-out causes same set of processing as bw failure
|
|
*/
|
|
fsm_cac_process_bw_failed_resp();
|
|
|
|
}
|
|
|