FreeCalypso > hg > freecalypso-sw
view gsm-fw/g23m-aci/aci_dti_mng/dti_conn_mng.c @ 982:461f7ee5f254
fc-olddump: brown paper bag
author | Mychaela Falconia <falcon@ivan.Harhan.ORG> |
---|---|
date | Thu, 10 Dec 2015 05:35:42 +0000 |
parents | c23e0dfa5154 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : ... | Modul : dti_conn_mng.c +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : Implementation of DTI Connection Manager +----------------------------------------------------------------------------- */ #ifndef DTI_CONN_MNG_C #define DTI_CONN_MNG_C #endif /*===== INCLUDES ===================================================*/ #include "config.h" #include "fixedconf.h" #include "condat-features.h" #include "aci_conf.h" #include "aci_all.h" #include "pconst.cdg" #include "mconst.cdg" #include "cnf_aci.h" #include "mon_aci.h" #include "pei.h" #include "aci_cmh.h" #include "ati_cmd.h" #include "aci_io.h" #include "aci_cmh.h" #include "aci_lst.h" #include "aci_mem.h" #include "dti.h" #include "dti_conn_mng.h" #include "dti_cntrl_mng.h" LOCAL ULONG used_dti_channels = 0; LOCAL T_ACI_LIST *dti_channel_list = NULL; /* list_begin */ LOCAL T_DTI_CONN_PARAMS glob_params; /********************** LOCAL FUNCTIONS *****************************/ LOCAL UBYTE dti_conn_get_new_dti_id (void) { ULONG tst_id; UBYTE i; TRACE_FUNCTION("dti_conn_get_new_dti_id()"); /* create a new DTI ID */ for (i = 0; i <= MAX_DTI_CONN_CHANNELS; i++) { tst_id = (0x01 << i) & used_dti_channels; if (!tst_id) { break; } } if (tst_id) { TRACE_EVENT("No DTI ID available"); return (DTI_DTI_ID_NOTPRESENT); } used_dti_channels |= (0x01 << i); TRACE_EVENT_P1("DTI ID %d created", i); return (i); } LOCAL void dti_conn_remove_dti_id (UBYTE dti_id) { ULONG tst_id; TRACE_FUNCTION("dti_conn_remove_id()"); if (dti_id >= MAX_DTI_CONN_CHANNELS) return; tst_id = 0x01 << (dti_id); used_dti_channels &= ~tst_id; TRACE_EVENT_P1("DTI ID %d removed", dti_id); } LOCAL BOOL dti_conn_error_cb(UBYTE dti_id, T_DTI_CONN_STATE result_type) { /* theorically should not be called... Yet helpfull for testing */ TRACE_FUNCTION("dti_conn_error_cb()"); TRACE_EVENT("ERROR: DTI connection callback has not been initialized !"); return FALSE; } LOCAL void dti_conn_reset_conn_parms( T_DTI_CONN_CHANNEL *dti_channel ) { UBYTE i,j; TRACE_FUNCTION("dti_conn_reset_conn_parms()"); dti_channel->erase_channel = FALSE; dti_channel->num_of_conns = 0; dti_channel->conn_cb = dti_conn_error_cb; dti_channel->state = DTI_CONN_STATE_DISCONNECTED; for (i=0; i<MAX_DTI_CONN_TUPLES; i++) { dti_channel->tuple_list[i].state = DTI_CONN_STATE_DISCONNECTED; for (j=0; j<NUM_OF_PEERS; j++) { dti_channel->tuple_list[i].peers[j].state = DTI_CONN_STATE_DISCONNECTED; dti_channel->tuple_list[i].peers[j].ent_id = DTI_ENTITY_INVALID; } } } LOCAL BOOL DTItest_dti_id( UBYTE dti_id, void *elem) { T_DTI_CONN_CHANNEL *dti_channel = (T_DTI_CONN_CHANNEL *)elem; if (dti_channel EQ NULL) return FALSE; if (dti_channel -> dti_id EQ dti_id ) return TRUE; else return FALSE; } LOCAL T_DTI_CONN_TUPLE *dti_conn_find_dti_tuple( T_DTI_CONN_CHANNEL *dti_channel, UBYTE tuple_no) { return &(dti_channel->tuple_list[tuple_no]); } LOCAL T_DTI_CONN_CHANNEL *dti_conn_find_dti_conn( UBYTE dti_id ) { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_find_dti_conn()"); /*find channel in list */ dti_channel = find_element (dti_channel_list, dti_id, DTItest_dti_id); return dti_channel; } LOCAL BOOL dti_conn_connect( T_DTI_CONN_CHANNEL* dti_channel, T_DTI_ENTITY_ID* entity_list, UBYTE num_entities, T_DTI_CONN_MODE mode ) { ULONG link_id; UBYTE tuple_no; UBYTE i; TRACE_FUNCTION("dti_conn_connect()"); dti_channel->state = DTI_CONN_STATE_CONNECTING; if (dti_channel->conn_cb) { (void )dti_channel->conn_cb(dti_channel->dti_id, DTI_CONN_STATE_CONNECTING); } else { TRACE_EVENT("conn_cb is NULL"); } if (mode EQ APPEND) { tuple_no = dti_channel->num_of_conns; } else /* SPLIT */ { tuple_no = 0; dti_channel->num_of_conns = 0; } for (i=0; i<num_entities-1; i++) { dti_channel->tuple_list[tuple_no].peers[0].ent_id = entity_list[i]; dti_channel->tuple_list[tuple_no].peers[1].ent_id = entity_list[i+1]; if ( (dti_channel->tuple_list[tuple_no].state NEQ DTI_CONN_STATE_DISCONNECTING) AND (dti_channel->tuple_list[tuple_no].state NEQ DTI_CONN_STATE_CONNECTING) ) { dti_channel->tuple_list[tuple_no].state = DTI_CONN_STATE_CONNECTING; dti_channel->tuple_list[tuple_no].tuple_no = tuple_no; dti_channel->state = DTI_CONN_STATE_CONNECTING; link_id = dti_conn_compose_link_id(0, 0, dti_channel->dti_id, tuple_no); dti_channel->tuple_list[tuple_no].peers[0].state = DTI_CONN_STATE_CONNECTING; dti_channel->tuple_list[tuple_no].peers[1].state = DTI_CONN_STATE_CONNECTING; /* connect a tuple */ (void) glob_params.mng_ent_cb(link_id, entity_list[i], entity_list[i+1], DTI_CONNECT); (void)glob_params.mng_ent_cb(link_id, entity_list[i+1], entity_list[i], DTI_CONNECT); } tuple_no++; } dti_channel->num_of_conns = tuple_no; return TRUE; } LOCAL BOOL dti_conn_disconnect( T_DTI_CONN_CHANNEL* dti_channel ) { ULONG link_id; UBYTE i; TRACE_FUNCTION("dti_conn_disconnect()"); dti_channel->state = DTI_CONN_STATE_DISCONNECTING; if (dti_channel->conn_cb) { (void)dti_channel->conn_cb(dti_channel->dti_id, DTI_CONN_STATE_DISCONNECTING); } else { TRACE_EVENT("conn_cb is NULL"); } for (i=0; i < dti_channel->num_of_conns; i++) { /* set tuple state only if it is not already DISCONNECTED */ if (dti_channel->tuple_list[i].state NEQ DTI_CONN_STATE_DISCONNECTED) { dti_channel->tuple_list[i].state = DTI_CONN_STATE_DISCONNECTING; } link_id = dti_conn_compose_link_id(0, 0, dti_channel->dti_id, i); /* disconnect only a connected entity */ if (dti_channel->tuple_list[i].peers[0].state EQ DTI_CONN_STATE_CONNECTED OR dti_channel->tuple_list[i].peers[0].state EQ DTI_CONN_STATE_CONNECTING ) { dti_channel->tuple_list[i].peers[0].state = DTI_CONN_STATE_DISCONNECTING; (void)glob_params.mng_ent_cb(link_id, dti_channel->tuple_list[i].peers[0].ent_id, dti_channel->tuple_list[i].peers[1].ent_id, DTI_DISCONNECT); } /* disconnect only a connected entity */ if (dti_channel->tuple_list[i].peers[1].state EQ DTI_CONN_STATE_CONNECTED OR dti_channel->tuple_list[i].peers[1].state EQ DTI_CONN_STATE_CONNECTING ) { dti_channel->tuple_list[i].peers[1].state = DTI_CONN_STATE_DISCONNECTING; (void)glob_params.mng_ent_cb(link_id, dti_channel->tuple_list[i].peers[1].ent_id, dti_channel->tuple_list[i].peers[0].ent_id, DTI_DISCONNECT); } } return TRUE; } /********************** GLOBAL FUNCTIONS *****************************/ GLOBAL T_DTI_CONN_LINK_ID dti_conn_compose_link_id(UBYTE dummy, UBYTE assoc, UBYTE dti_id, UBYTE tuple_no) { T_DTI_CONN_LINK_ID link_id = 0; link_id += dummy; link_id <<= 8; link_id += assoc; link_id <<= 8; link_id += dti_id; link_id <<= 8; link_id += tuple_no; return link_id; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_init | +--------------------------------------------------------------------+ PURPOSE : initialise the DTI Connection Manager */ GLOBAL void dti_conn_init( T_DTI_CONN_MNG_ENT_CB* mng_ent_cb ) { TRACE_FUNCTION("dti_conn_init()"); dti_channel_list = new_list (); glob_params.conn_cb = NULL; glob_params.mng_ent_cb = mng_ent_cb; glob_params.num_entities = 0; } /* +--------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_new | +--------------------------------------------------------------------+ PURPOSE : register new DTI channel */ GLOBAL UBYTE dti_conn_new(UBYTE dti_id ) { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_new()"); if (dti_id EQ DTI_DTI_ID_NOTPRESENT) { dti_id = dti_conn_get_new_dti_id (); } if (dti_id EQ DTI_DTI_ID_NOTPRESENT) { return (DTI_DTI_ID_NOTPRESENT); } /* search for an existing entry with correspondant dti_id */ dti_channel = dti_conn_find_dti_conn (dti_id); if( dti_channel ) { return (DTI_DTI_ID_NOTPRESENT); /* couldn't create a new entry */ } ACI_MALLOC(dti_channel, sizeof(T_DTI_CONN_CHANNEL)); dti_conn_reset_conn_parms (dti_channel); dti_channel->dti_id = dti_id; insert_list(dti_channel_list, dti_channel); return (dti_channel->dti_id); } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_erase_entry | +---------------------------------------------------------------------+ PURPOSE : erase entry from DTI channel list */ GLOBAL void dti_conn_erase_entry(UBYTE dti_id) { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_erase_entry"); /* find element to be erased */ dti_channel = remove_element (dti_channel_list, dti_id, DTItest_dti_id); if( dti_channel NEQ NULL ) /* entry not erased yet */ ACI_MFREE (dti_channel); dti_conn_remove_dti_id(dti_id); } /* +-----------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_is_dti_channel_connected | +-----------------------------------------------------------------------+ PURPOSE : returns TRUE if end-to-end DTI connection is connected and the given entity is in this connection */ GLOBAL BOOL dti_conn_is_dti_channel_connected( T_DTI_ENTITY_ID ent_id, UBYTE dti_id ) { UBYTE count = 0; UBYTE i; UBYTE entity_found = FALSE; T_DTI_CONN_CHANNEL *dti_channel = dti_conn_find_dti_conn( dti_id ); TRACE_FUNCTION("dti_conn_is_dti_channel_connected()"); if (dti_channel EQ NULL) { TRACE_EVENT_P1("dti_channel for dti_id %d not found", dti_id); return FALSE; } for (i=0; i<dti_channel->num_of_conns; i++) { if ((dti_channel->tuple_list[i].peers[0].ent_id EQ ent_id) OR (dti_channel->tuple_list[i].peers[1].ent_id EQ ent_id)) { entity_found = TRUE; break; } } if (entity_found EQ FALSE) return FALSE; if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED) { return TRUE; } else { for (i=0; i<dti_channel->num_of_conns; i++) { if (dti_channel->tuple_list[i].state EQ DTI_CONN_STATE_CONNECTED) { count++; } } if (count EQ dti_channel->num_of_conns) { return TRUE; } } return FALSE; } /* +--------------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_is_dti_channel_disconnected | +--------------------------------------------------------------------------+ PURPOSE : returns TRUE if end-to-end DTI connection is disconnected */ GLOBAL BOOL dti_conn_is_dti_channel_disconnected( UBYTE dti_id ) { UBYTE count = 0; UBYTE i; T_DTI_CONN_CHANNEL *dti_channel = dti_conn_find_dti_conn( dti_id ); TRACE_FUNCTION("dti_conn_is_dti_channel_disconnected()"); if (dti_channel EQ NULL) { return TRUE; } if (dti_channel->state EQ DTI_CONN_STATE_DISCONNECTED) { return TRUE; } else { for (i=0; i<dti_channel->num_of_conns; i++) { if (dti_channel->tuple_list[i].state EQ DTI_CONN_STATE_DISCONNECTED) { count++; } } if (count EQ dti_channel->num_of_conns) { return TRUE; } } return FALSE; } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_est_dpath | +---------------------------------------------------------------------+ PURPOSE : establishes data path. */ GLOBAL BOOL dti_conn_est_dpath( UBYTE dti_id, T_DTI_ENTITY_ID* entity_list, UBYTE num_entities, T_DTI_CONN_MODE mode, T_DTI_CONN_CB* cb) { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_est_dpath()"); /*find channel in list */ dti_channel = dti_conn_find_dti_conn (dti_id); if (dti_channel EQ NULL) { TRACE_EVENT_P1("[ERR] dti_conn_est_dpath: dti_channel dti_id=%x not found", dti_id); /* DTI ID not found */ return FALSE; } if ( entity_list[0] EQ DTI_ENTITY_INVALID OR entity_list[1] EQ DTI_ENTITY_INVALID) { /* improper entity list */ TRACE_EVENT("[ERR] improper entity list "); return FALSE; } /* if 'SPLIT' then the whole DTI channel must be disconnected before a * new connection is established */ if ((mode EQ SPLIT) AND (dti_channel->state NEQ DTI_CONN_STATE_DISCONNECTED)) { dti_conn_disconnect (dti_channel); /* save new entity list to entity list buffer */ memcpy(glob_params.entity_list_buf, entity_list, sizeof(T_DTI_ENTITY_ID)*num_entities); glob_params.num_entities = num_entities; glob_params.conn_cb = cb; } else { dti_channel->conn_cb = cb; dti_conn_connect (dti_channel, entity_list, num_entities, mode); } return TRUE; } /* +---------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_close_dpath | +---------------------------------------------------------------------+ PURPOSE : closes a DTI connection */ GLOBAL BOOL dti_conn_close_dpath( UBYTE dti_id ) { T_DTI_CONN_CHANNEL *dti_channel; TRACE_FUNCTION("dti_conn_close_dpath()"); dti_channel = dti_conn_find_dti_conn( dti_id ); if (dti_channel EQ NULL) { TRACE_EVENT_P1("[ERR] dti_conn_close_dpath: dti_channel dti_id=%x not found", dti_id); return FALSE; } if (dti_channel->state NEQ DTI_CONN_STATE_DISCONNECTED) { dti_channel->state = DTI_CONN_STATE_DISCONNECTING; dti_conn_disconnect (dti_channel); } else { TRACE_EVENT("[ERR] dti_conn_close_dpath: try to close dpath which was DISCONNECTED"); return FALSE; } return TRUE; } /* +-----------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_entity_connected | +-----------------------------------------------------------------------+ PURPOSE : response after a DTI connect request. This function is called to inform the DTI Connection Manager that a connection is established. */ GLOBAL void dti_conn_entity_connected( T_DTI_CONN_LINK_ID link_id, T_DTI_ENTITY_ID ent_id, T_DTI_CONN_RESULT result ) { T_DTI_CONN_CHANNEL *dti_channel; T_DTI_CONN_TUPLE *tuple; UBYTE i; UBYTE dti_id = EXTRACT_DTI_ID(link_id); BOOL both_entities_connected = FALSE; UBYTE count = 0; TRACE_FUNCTION("dti_conn_entity_connected()"); dti_channel = dti_conn_find_dti_conn( dti_id ); if (dti_channel EQ NULL) { TRACE_EVENT_P1("[ERR] dti_conn_entity_connected: dti_channel link_id=%x not found", link_id); return; } if (result EQ DTI_ERROR) { /* mark entity as disconnected */ dti_conn_entity_disconnected( link_id, ent_id ); /* close the whole DTI channel */ dti_conn_close_dpath( dti_id ); return; } if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED) { TRACE_EVENT_P1("dti channel with dti_id=%x already connected", dti_id); return; } tuple = dti_conn_find_dti_tuple( dti_channel, EXTRACT_TUPLE_NO(link_id ) ); for (i=0; i<NUM_OF_PEERS; i++) { if (tuple->peers[i].state EQ DTI_CONN_STATE_CONNECTED) { count++; } if (tuple->peers[i].ent_id EQ ent_id) { if (tuple->peers[i].state EQ DTI_CONN_STATE_CONNECTING) { tuple->peers[i].state = DTI_CONN_STATE_CONNECTED; count++; } } if (count EQ NUM_OF_PEERS) { both_entities_connected = TRUE; } } /* if both entities are CONNECTED */ if (both_entities_connected) { tuple->state = DTI_CONN_STATE_CONNECTED; /* if all other tuples CONNECTED */ if (dti_conn_is_dti_channel_connected(ent_id, dti_id)) { dti_channel->state = DTI_CONN_STATE_CONNECTED; TRACE_EVENT_P1("DTI ID %d connected", dti_id); /* call connect_cb here */ if (dti_channel->conn_cb) { (void)dti_channel->conn_cb(dti_id, DTI_CONN_STATE_CONNECTED); } else { TRACE_EVENT("conn_cb is NULL"); } } } } /* +-----------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_entity_disconnected | +-----------------------------------------------------------------------+ PURPOSE : response after a DTI connect request. This function is called to inform the DTI Connection Manager that a connection is closed. */ GLOBAL void dti_conn_entity_disconnected( T_DTI_CONN_LINK_ID link_id, T_DTI_ENTITY_ID ent_id ) { T_DTI_CONN_CHANNEL *dti_channel; T_DTI_CONN_TUPLE *tuple; UBYTE i; UBYTE dti_id = EXTRACT_DTI_ID(link_id); UBYTE count = 0; TRACE_FUNCTION("dti_conn_entity_disconnected()"); dti_channel = dti_conn_find_dti_conn( dti_id ); if (dti_channel EQ NULL) { TRACE_EVENT_P1("[ERR] dti_conn_entity_disconnected: dti_channel link_id=%x not found", link_id); return; } if (dti_channel->state EQ DTI_CONN_STATE_DISCONNECTED) { TRACE_EVENT_P1("dti channel with dti_id=%x already diconnected", dti_id); return; } tuple = dti_conn_find_dti_tuple( dti_channel, EXTRACT_TUPLE_NO(link_id) ); for (i=0; i<NUM_OF_PEERS; i++) { if (tuple->peers[i].state EQ DTI_CONN_STATE_DISCONNECTED) { count++; } /* find disconnected entity */ if (tuple->peers[i].ent_id EQ ent_id) { tuple->peers[i].state = DTI_CONN_STATE_DISCONNECTED; tuple->peers[i].ent_id = DTI_ENTITY_INVALID; count++; tuple->state = DTI_CONN_STATE_DISCONNECTING; if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED) { /* set DTI channel state */ dti_channel->state = DTI_CONN_STATE_DISCONNECTING; } } } /* if both entities are DISCONNECTED */ if (count EQ NUM_OF_PEERS) { /* set tuple state */ tuple->state = DTI_CONN_STATE_DISCONNECTED; /* if all other tuples DISCONNECTED */ if (dti_conn_is_dti_channel_disconnected(dti_id)) { dti_channel->state = DTI_CONN_STATE_DISCONNECTED; TRACE_EVENT_P1("DTI ID %d disconnected", dti_id); /* reset number of conns */ dti_channel->num_of_conns = 0; /* call disconnect_cb here */ if (dti_channel->conn_cb) { (void)dti_channel->conn_cb(dti_id, DTI_CONN_STATE_DISCONNECTED); } else { TRACE_EVENT("conn_cb is NULL"); } if (glob_params.num_entities NEQ 0) { dti_channel->conn_cb = glob_params.conn_cb; dti_conn_connect( dti_channel, glob_params.entity_list_buf, glob_params.num_entities, SPLIT ); glob_params.num_entities = 0; } else { if (dti_channel->erase_channel EQ TRUE) { /* erase entry in DTI Conn Mng */ dti_conn_erase_entry(dti_id); } } } } } /* +-----------------------------------------------------------------------+ | PROJECT : MODULE : DTI_CONN | | STATE : code ROUTINE : dti_conn_close_all_connections| +-----------------------------------------------------------------------+ PURPOSE : This function is called to close all established DTI connections. */ GLOBAL void dti_conn_close_all_connections() { T_DTI_CONN_CHANNEL *dti_channel=NULL; TRACE_FUNCTION("dti_conn_close_all_connections()"); while(TRUE) { dti_channel = get_next_element (dti_channel_list, dti_channel); if (dti_channel EQ NULL) { return; } if (dti_channel->state EQ DTI_CONN_STATE_CONNECTED) { dti_conn_close_dpath(dti_channel->dti_id); dti_channel->erase_channel = TRUE; } else { dti_conn_erase_entry(dti_channel->dti_id); } } }