FreeCalypso > hg > fc-selenite
diff src/g23m-gprs/llc/llc_txf.c @ 1:d393cd9bb723
src/g23m-*: initial import from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 15 Jul 2018 04:40:46 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g23m-gprs/llc/llc_txf.c Sun Jul 15 04:40:46 2018 +0000 @@ -0,0 +1,977 @@ +/* ++----------------------------------------------------------------------------- +| Project : +| Modul : ++----------------------------------------------------------------------------- +| 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 : This modul is part of the entity LLC and implements all +| procedures and functions as described in the +| SDL-documentation (TX-statemachine) ++----------------------------------------------------------------------------- +*/ + +#ifndef LLC_TXF_C +#define LLC_TXF_C +#endif + +#define ENTITY_LLC + +/*==== INCLUDES =============================================================*/ + +#include <string.h> /* to get memcpy() */ + +#include "typedefs.h" /* to get Condat data types */ +#include "vsi.h" /* to get a lot of macros */ +#include "macdef.h" +#include "gprs.h" +#include "gsm.h" /* to get a lot of macros */ +#include "cnf_llc.h" /* to get cnf-definitions */ +#include "mon_llc.h" /* to get mon-definitions */ +#include "prim.h" /* to get the definitions of used SAP and directions */ +#include "llc.h" /* to get the global entity definitions */ + +#include "llc_f.h" /* to get global functions, e.g. llc_generate_input */ +#include "llc_txf.h" /* to get the global entity definitions */ +#include "llc_txp.h" /* to get the function tx_cci_cipher_cnf */ + +#include "llc_uitxs.h" /* to get signal interface to UITX */ +#include "llc_itxs.h" /* to get signal interface to ITX */ + +#ifndef TI_PS_OP_CIPH_DRIVER +#include "cci_fbsf.h" /* to get functional interface */ +#endif + + +/*==== CONST ================================================================*/ + +/*==== LOCAL VARS ===========================================================*/ + +/*==== PRIVATE FUNCTIONS ====================================================*/ + +/*==== PUBLIC FUNCTIONS =====================================================*/ + + +/* ++------------------------------------------------------------------------------ +| Function : tx_init ++------------------------------------------------------------------------------ +| Description : This procedure initialises all necessary variables of send_pdu. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void llc_tx_init (void) +{ + TRACE_FUNCTION( "tx_init" ); + + /* + * Initialise TX with state NOT_READY. + */ + INIT_STATE (TX, TX_TLLI_UNASSIGNED_NOT_READY); + + /* + * Flush TX queue, if there is (in case of an LLC + * restart) old stuff queued. + */ + tx_clear_buffer(); + + return; +} /* tx_init() */ + + +/* ++------------------------------------------------------------------------------ +| Function : tx_clear_buffer ++------------------------------------------------------------------------------ +| Description : This procedure frees all buffered CCI_CIPHER_CNF primitives. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void tx_clear_buffer (void) +{ + T_TX_QUEUE *elem; + T_TX_QUEUE *elem_next; + + + TRACE_FUNCTION( "tx_clear_buffer" ); + + for (elem = llc_data->tx.queue; elem NEQ NULL; elem = elem_next) + { + elem_next = elem->next; + + /* + * Free primitive if any is stored in queue element. + */ + if (elem->primitive NEQ (ULONG)NULL) + { + PFREE (elem->primitive); + } + + MFREE (elem); + } + + llc_data->tx.queue = NULL; + + /* + * Initialise UITX space counter for each SAPI. + */ + llc_data->tx.queue_counter_uitx[0] = UITX_1_QUEUE_SIZE; + llc_data->tx.queue_counter_uitx[1] = UITX_3_QUEUE_SIZE; + llc_data->tx.queue_counter_uitx[2] = UITX_5_QUEUE_SIZE; + llc_data->tx.queue_counter_uitx[3] = UITX_7_QUEUE_SIZE; + llc_data->tx.queue_counter_uitx[4] = UITX_9_QUEUE_SIZE; + llc_data->tx.queue_counter_uitx[5] = UITX_11_QUEUE_SIZE; + + /* + * Initialise ITX space counter for each SAPI. + */ + llc_data->tx.queue_counter_itx[0] = ITX_3_QUEUE_SIZE; + llc_data->tx.queue_counter_itx[1] = ITX_5_QUEUE_SIZE; + llc_data->tx.queue_counter_itx[2] = ITX_9_QUEUE_SIZE; + llc_data->tx.queue_counter_itx[3] = ITX_11_QUEUE_SIZE; + + return; +} /* tx_clear_buffer() */ + +/* ++------------------------------------------------------------------------------ +| Function : tx_cipher_req ++------------------------------------------------------------------------------ +| Description : Handles the function tx_cipher_req. This functions sets the +| ciphering parameters and calls the ciphering driver function. +| +| Parameters : todo +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void tx_cipher_req +( +#ifdef LL_DESC +T_CCI_CIPHER_DESC_REQ *cipher_req +#else +T_CCI_CIPHER_REQ *cipher_req +#endif +) + +{ + T_CIPH_init_cipher_req_parms init_cipher_req_parms; + T_CIPH_cipher_req_parms cipher_req_parms; + T_CIPH_in_data_list in_data_list; + T_CIPH_out_data out_data; + T_CIPH_ck ck; + U16 i; + U8 status; + + TRACE_FUNCTION( "tx_cipher_req" ); + +#ifdef LLC_TRACE_CIPHERING + TRACE_EVENT("UPLINK NON CIPHERED DATA"); + llc_trace_desc_list3_content(cipher_req->desc_list3); +#endif + /* + * Copy pointer to desc's from CIPHER_REQ to the in_data_list + * The in_data array in allocated dynamically in this func. + */ + llc_copy_ul_data_to_list(cipher_req, &in_data_list); + /* + * Store ciphering parameters + */ + cipher_req_parms.gprs_parameters.pm = cipher_req->pm; + cipher_req_parms.gprs_parameters.header_size = cipher_req->header_size; + cipher_req_parms.gprs_parameters.ciphering_input = cipher_req->ciphering_input; + cipher_req_parms.gprs_parameters.threshold = 0; + init_cipher_req_parms.direction = CIPH_UPLINK_DIR; + init_cipher_req_parms.algo = cipher_req->ciphering_algorithm; + init_cipher_req_parms.ptr_ck = & ck; + /* + * Copy ciphering key + */ + for (i=0; i<8;i++){ + init_cipher_req_parms.ptr_ck->ck_element[i] = cipher_req->kc.key[i]; + } + + { + /* Use GRLC_DATA_REQ instead of CCI_CIPHER_CNF to avoid PPASS in LLC*/ + PALLOC_SDU (grlc_data_req, GRLC_DATA_REQ, + (USHORT)(cipher_req->desc_list3.list_len*8 + FCS_SIZE_BITS)); + + grlc_data_req->sdu.o_buf = 0; + grlc_data_req->sdu.l_buf = 0; + out_data.buf = (U32)(&grlc_data_req->sdu.buf[grlc_data_req->sdu.o_buf]); + /* + * Initialize ciphering driver and cipher data + */ +#ifdef TI_PS_OP_CIPH_DRIVER + ciph_init_cipher_req (&init_cipher_req_parms, NULL); + ciph_cipher_req (&cipher_req_parms, &in_data_list, &out_data, &status); +#else + ciph_init_cipher_req_sim (&init_cipher_req_parms, NULL); + ciph_cipher_req_sim (&cipher_req_parms, &in_data_list, &out_data, &status); +#endif + + /* + * "Send" CIPHER_CNF to LLC + */ + grlc_data_req->sdu.l_buf = out_data.len * 8; + grlc_data_req->tlli = cipher_req->reference1; + +#ifdef LLC_TRACE_CIPHERING + TRACE_EVENT("UPLINK CIPHERED DATA"); + llc_trace_sdu(&grlc_data_req->sdu); +#endif + tx_cci_cipher_cnf (grlc_data_req); + + } + /* + * Remove in use mark from the cipher request primitive + */ + if (cipher_req != NULL) { + { + /* + * Free cipher request, if not further used by other entities + */ + if (cipher_req->attached_counter == CCI_NO_ATTACHE) { +#ifdef LL_DESC + llc_cl_desc3_free((T_desc3*)cipher_req->desc_list3.first); +#endif /* LL_DESC */ + } + } + MFREE (cipher_req); + cipher_req = NULL; + } + /* + * Free in_data array from in_data_list + * allocated dynamically in llc_copy_ul_data_to_list() + */ + if(in_data_list.ptr_in_data != NULL){ + MFREE(in_data_list.ptr_in_data); + in_data_list.ptr_in_data = NULL; + } + +} /* tx_cipher_req() */ + +/* ++------------------------------------------------------------------------------ +| Function : tx_send_cipher_req ++------------------------------------------------------------------------------ +| Description : This procedure fills all necessary parameters in the primitive +| CCI_CIPHER_REQ and sends the primitive to CCI. +| +| Parameters : cci_cipher_req - a valid pointer to a CCI_CIPHER_REQ primitive +| frame_type - indicates frame type (e.g. UI_FRAME) +| protected_mode - PM bit setting for CCI_CIPHER_REQ +| ns - N(U) for UI frames +| cipher - indicates if frame shall be ciphered or not +| oc - +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void tx_send_cipher_req +( +#ifdef LL_DESC + T_CCI_CIPHER_DESC_REQ *cci_cipher_desc_req, +#else + T_CCI_CIPHER_REQ *cci_cipher_desc_req, +#endif + T_PDU_TYPE frame_type, + UBYTE protected_mode, + T_FRAME_NUM ns, + UBYTE cipher, + ULONG oc +) +{ + TRACE_FUNCTION( "tx_send_cipher_req" ); + + cci_cipher_desc_req->pm = protected_mode; + + if ( (cipher EQ LL_CIPHER_ON) AND + (llc_data->ciphering_algorithm NEQ LLGMM_CIPHER_NO_ALGORITHM) ) + { + cci_cipher_desc_req->ciphering_algorithm = llc_data->ciphering_algorithm; + memcpy (&cci_cipher_desc_req->kc, &llc_data->kc, sizeof(T_kc)); + + llc_generate_input (llc_data->current_sapi, frame_type, ns, + &cci_cipher_desc_req->ciphering_input, oc); + + cci_cipher_desc_req->direction = CCI_DIRECTION_UPLINK; + } + else /* LL_CIPHER_OFF */ + { + cci_cipher_desc_req->ciphering_algorithm = CCI_CIPHER_NO_ALGORITHM; + } + + tx_cipher_req (cci_cipher_desc_req); + return; +} /* tx_send_cipher_desc_req() */ + + +/* ++------------------------------------------------------------------------------ +| Function : tx_reserve_buffer ++------------------------------------------------------------------------------ +| Description : This procedure allocates an element for the local transmit +| queue. If cause is DEFAULT or MOBILITY_MANAGEMENT, the element +| is appended at the end of the queue, otherwise it is inserted +| at the beginning. Necessary data like primitive header +| information and additional important data for the (resulting) +| GRLC_xDATA_REQ primitive is stored in the reserved buffer +| element. The primitive pointer in the element is set to NULL, +| to indicate that the element is not yet 'ready to send'. +| Parameter reservation_no will be set to the allocation number +| of the element. Parameter buffer_available will be set to TRUE +| if additional data primitives can be buffered for the current +| sapi, otherwise it will be set to FALSE. +| +| Parameters : ll_unitdata_req - a valid pointer to a LL_UNITDATA_REQ +| primitive, containing the data to be sent +| prim_type - indicates GRLC_DATA/UNITDATA_REQ +| cause - frame cause, only valid for GRLC_DATA_REQ +| rx_service - service for flow control (if any) +| reservation_no - associated number for the buffer entry +| buffer_available - still buffer space available for current +| SAPI +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void tx_reserve_buffer + ( +#ifdef LL_DESC + T_LL_UNITDESC_REQ *ll_unitdesc_req, +#else + T_LL_UNITDATA_REQ *ll_unitdesc_req, +#endif + T_PRIM_TYPE prim_type, + UBYTE cause, + T_SERVICE rx_service, + ULONG *reservation_no, + BOOL *buffer_available + ) +{ + T_TX_QUEUE *elem; + T_TX_QUEUE **insert; + + static ULONG allocation_number = 0; + + TRACE_FUNCTION ("tx_reserve_buffer"); + + MALLOC (elem, sizeof(T_TX_QUEUE)); + + /* + * Increase allocation number. Use of reservation_no must correspond + * to use in tx_store_buffer(). + */ + *reservation_no = ++(allocation_number); + + /* + * Store all required information in new queue element. Member primitive + * is set to NULL to indicate that the element is not yet ready to be sent. + * Copy necessary primitive header information to ph_* variables. + */ + elem->primitive = (ULONG)NULL; + elem->prim_type = prim_type; + elem->reference = allocation_number; + elem->rx_service = rx_service; + elem->remove_frame = FALSE; + elem->ph_sapi = ll_unitdesc_req->sapi; + elem->ph_tlli = ll_unitdesc_req->tlli; + elem->ph_grlc_qos_peak = ll_unitdesc_req->ll_qos.peak; + elem->ph_radio_prio = ll_unitdesc_req->radio_prio; + elem->ph_cause = cause; +#ifdef REL99 + elem->ph_pkt_flow_id = (UBYTE)ll_unitdesc_req->pkt_flow_id; +#endif /* REL99 */ + + if ((cause EQ GRLC_DTACS_DEF) OR (cause EQ GRLC_DTACS_MOBILITY_MANAGEMENT)) + { + /* + * "Normal" frame cause, append element at the end of queue. Let insert + * either point to llc_data->tx.queue or to the member .next of an element. + */ + insert = &llc_data->tx.queue; + while (*insert NEQ NULL) + { + insert = &((*insert)->next); + } + + /* + * Insert new element at found location and mark element as last in queue. + */ + *insert = elem; + elem->next = NULL; + } + else /* GRLC_DTACS_PAGE_RESPONSE OR GRLC_DTACS_CELL_UPDATE */ + { + /* + * No "normal" frame cause, thus LLGMM_TRIGGER_REQ must have been + * received. Insert element at the beginning of queue. + */ + elem->next = llc_data->tx.queue; + llc_data->tx.queue = elem; + } + + /* + * Check if a service for flow control is specified (currently only + * SERVICE_UITX and SERVICE_ITX are recognized). + */ + *buffer_available = FALSE; + + if (rx_service EQ SERVICE_UITX) + { + /* + * Decrement the space counter of UITX primitives in the queue for the + * current SAPI. This means that one place of the queue is occupied. + * Check if there is space for one more primitive in the queue. + */ + int n = llc_data->tx.queue_counter_uitx[UIMAP(llc_data->current_sapi)]; + + if (n > 0) + { + llc_data->tx.queue_counter_uitx[UIMAP(llc_data->current_sapi)]--; + + if (n > 1) + { + *buffer_available = TRUE; + } + } + else + { + TRACE_EVENT ("Check uitx-queue flow"); + } + } + else if (rx_service EQ SERVICE_ITX) + { + /* + * Decrement the space counter of ITX primitives in the queue for the + * current SAPI. This means that one place of the queue is occupied. + * Check if there is space for one more primitive in the queue. + */ + int n = llc_data->tx.queue_counter_itx[IMAP(llc_data->current_sapi)]; + + if (n > 0) + { + llc_data->tx.queue_counter_itx[IMAP(llc_data->current_sapi)]--; + + if (n > 1) + { + *buffer_available = TRUE; + } + } + else + { + TRACE_EVENT ("Check itx-queue flow"); + } + } + else + { + /* + * All other services (e.g. SERVICE_U) are allowed to send primitives + * per default. I.E. no flow control, except for service UITX and ITX. + */ + *buffer_available = TRUE; + } +} /* tx_reserve_buffer() */ + + +/* ++------------------------------------------------------------------------------ +| Function : tx_store_buffer ++------------------------------------------------------------------------------ +| Description : This procedure stores the given CCI primitive as GRLC primitive +| in the already reserved local transmit queue element that is +| given with primitive parameter reference. This queue element +| is marked as 'ready to send'. The CCI primitive is being +| PPASSED as GRLC_DATA_REQ/GRLC_UNITDATA_REQ, according to +| prim_type in the queue element. All header information for +| the GRLC primitive is being filled in from the already stored +| data in the element. +| +| Parameters : cci_cipher_cnf - a valid pointer to a CCI_CIPHER_CNF primitive +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void tx_store_buffer (T_GRLC_DATA_REQ *grlc_data_req) +{ + T_TX_QUEUE *elem = llc_data->tx.queue; + + + TRACE_FUNCTION ("tx_store_buffer"); + + /* + * Find corresponding queue entry. Use of reference must correspond to + * use in tx_reserve_buffer(). + */ + while (elem NEQ NULL) + { + if (elem->reference EQ grlc_data_req->tlli) + { + break; + } + + elem = elem->next; + } + + if (elem NEQ NULL) + { + if (elem->prim_type EQ PRIM_DATA) + { + /* + * Copy information from stored primitive header variables (ph_*) to + * GRLC primitive. + */ + grlc_data_req->sapi = elem->ph_sapi; + grlc_data_req->tlli = elem->ph_tlli; +#ifdef LL_2to1 + grlc_data_req->grlc_qos.peak = elem->ph_grlc_qos_peak; +#else + grlc_data_req->grlc_qos.peak = elem->ph_grlc_qos_peak; +#endif + grlc_data_req->radio_prio = elem->ph_radio_prio; + grlc_data_req->cause = elem->ph_cause; + +#ifdef REL99 + grlc_data_req->pkt_flow_id[0] = elem->ph_pkt_flow_id; +#endif /* REL99*/ + +#ifdef _SIMULATION_ + /* + * Initialize all (unused) members of grlc_qos, because otherwise the test + * cases fail. + */ +#ifdef LL_2to1 + grlc_data_req->grlc_qos.delay = PS_DELAY_SUB; + grlc_data_req->grlc_qos.relclass = PS_RELCLASS_SUB; + grlc_data_req->grlc_qos.preced = PS_PRECED_SUB; + grlc_data_req->grlc_qos.mean = PS_MEAN_SUB; +#else + grlc_data_req->grlc_qos.delay = GRLC_DELAY_SUB; + grlc_data_req->grlc_qos.relclass = GRLC_RELCLASS_SUB; + grlc_data_req->grlc_qos.preced = GRLC_PRECED_SUB; + grlc_data_req->grlc_qos.mean = GRLC_MEAN_SUB; +#endif + +#endif /* _SIMULATION_ */ + + elem->primitive = (ULONG)grlc_data_req; + } + else /* PRIM_UNITDATA */ + { + /* + * Store CCI primitive as GRLC_UNITDATA_REQ (and mark it as stored). + */ + PPASS (grlc_data_req, grlc_unitdata_req, GRLC_UNITDATA_REQ); + + /* + * Copy information from stored primitive header variables (ph_*) to + * GRLC primitive (omit ph_cause, because it is not present in + * GRLC_UNITDATA_REQ). + */ + grlc_unitdata_req->sapi = elem->ph_sapi; + grlc_unitdata_req->tlli = elem->ph_tlli; +#ifdef LL_2to1 + grlc_unitdata_req->grlc_qos.peak = elem->ph_grlc_qos_peak; +#else + grlc_unitdata_req->grlc_qos.peak = elem->ph_grlc_qos_peak; +#endif + grlc_unitdata_req->radio_prio = elem->ph_radio_prio; +#ifdef REL99 + grlc_unitdata_req->pkt_flow_id[0] = elem->ph_pkt_flow_id; +#endif /* REL99*/ +#ifdef _SIMULATION_ + /* + * Initialize all (unused) members of grlc_qos, because otherwise the test + * cases fail. + */ +#ifdef LL_2to1 + grlc_unitdata_req->grlc_qos.delay = PS_DELAY_SUB; + grlc_unitdata_req->grlc_qos.relclass = PS_RELCLASS_SUB; + grlc_unitdata_req->grlc_qos.preced = PS_PRECED_SUB; + grlc_unitdata_req->grlc_qos.mean = PS_MEAN_SUB; +#else + grlc_unitdata_req->grlc_qos.delay = GRLC_DELAY_SUB; + grlc_unitdata_req->grlc_qos.relclass = GRLC_RELCLASS_SUB; + grlc_unitdata_req->grlc_qos.preced = GRLC_PRECED_SUB; + grlc_unitdata_req->grlc_qos.mean = GRLC_MEAN_SUB; +#endif /* LL_2to1 */ + + + + +#endif /* _SIMULATION_ */ + + elem->primitive = (ULONG)grlc_unitdata_req; + } + } + else /* elem == NULL */ + { + /* + * elem not found is possible in case of an LLC re-init, reset, + * unassign, ... + */ + TRACE_0_INFO("No TX queue entry for given reference found"); + PFREE (grlc_data_req); + } + +} /* tx_store_buffer() */ + + +/* ++------------------------------------------------------------------------------ +| Function : tx_get_next_frame ++------------------------------------------------------------------------------ +| Description : When LLC is not suspended, this procedure gets (and removes) +| the first primitive out of the local transmit queue and stores +| it in one of the parameters, according to the type of the +| primitive (which is written in prim_type). If no frame is +| available in the queue (i.e. first queue element is not marked +| as 'ready to send', or the queue is empty), the value NO_PRIM +| is written in prim_type. The parameter rx_service indicates the +| originator service. In case the rx_service is UITX or ITX an +| READY signal for flow control will be send after frame +| transmission. +| When LLC is suspended, this procedure returns the first +| primitive for SAPI 1 or the first U frame for any SAPI, which +| is ready to send. +| +| Parameters : grlc_data_req - a valid pointer to a pointer to a GRLC-DATA-REQ +| primitive +| grlc_unitdata_req - a valid pointer to a pointer to a +| GRLC-UNITDATA-REQ primitive +| prim_type - will be set to PRIM_DATA or PRIM_UNITDATA, must be +| a valid pointer +| rx_service - indicates the originater service +| must be a valid pointer +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void tx_get_next_frame (T_GRLC_DATA_REQ **grlc_data_req, + T_GRLC_UNITDATA_REQ **grlc_unitdata_req, + T_PRIM_TYPE *prim_type, + T_SERVICE *rx_service, + UBYTE *sapi) +{ + int frame_len; + int ctrl_len; + T_TX_QUEUE *elem; + T_TX_QUEUE **find; + + + TRACE_FUNCTION( "tx_get_next_frame" ); + + + /* + * Initialise find w/ queue start. find points always to the element + * "before" the examined one, to be able to modifiy the queue, if + * an element is found. + */ + find = &llc_data->tx.queue; + + /* + * If LLC is suspended search the queue for the first GRLC_DATA_REQ primitive, + * otherwise take the first primitive in queue (if any). + */ + if (llc_data->suspended EQ TRUE) + { + /* + * LLC is in suspended mode. Search the queue for the first primitive + * for SAPI 1 or the first U frame for any SAPI + */ + while ( (*find NEQ NULL) AND + ((*find)->ph_sapi NEQ LL_SAPI_1) AND + ((*find)->rx_service NEQ SERVICE_U) AND + ((*find)->primitive NEQ (ULONG)NULL) ) + { + find = &((*find)->next); + } + } + + /* + * Let elem point to queue element (NULL, if no element present/found). + */ + elem = *find; + + + /* + * Check if queue is empty or "first" queue element (depending on suspended + * mode) is marked as not 'ready to send', i.e. it contains a NULL + * primitive pointer. + */ + if ((elem EQ NULL) OR (elem->primitive EQ (ULONG)NULL)) + { + /* + * Queue is empty or "first" element is not yet 'ready to send'. + */ + *prim_type = NO_PRIM; + } + else /* (elem NEQ NULL) AND (elem->primitive NEQ NULL) */ + { + /* + * Found a valid (and 'ready to send') element in queue. + */ + + /* + * Remove found element from queue (set member next of element before + * the found element to the element behind the found element and thus + * skip the found element). + */ + *find = (*find)->next; + + /* + * Store data of element in the given parameters. + */ + *prim_type = elem->prim_type; + *rx_service = elem->rx_service; + *sapi = elem->ph_sapi; + + if (elem->prim_type EQ PRIM_DATA) + { + *grlc_data_req = (T_GRLC_DATA_REQ *)elem->primitive; + + frame_len = BYTELEN((*grlc_data_req)->sdu.l_buf); + } + else /* PRIM_UNITDATA */ + { + *grlc_unitdata_req = (T_GRLC_UNITDATA_REQ *)elem->primitive; + + frame_len = BYTELEN((*grlc_unitdata_req)->sdu.l_buf); + } + + /* + * If the information fild doesn't fit in current N201_U, remove frame + * (only applies to service U and UITX). + */ + if (*rx_service == SERVICE_U || *rx_service == SERVICE_UITX) + { + ctrl_len = (*rx_service == SERVICE_U) ? U_FRAME_MIN_OCTETS + : UI_FRAME_MIN_OCTETS; + + if (frame_len > llc_data->n201_u_base[UIMAP(*sapi)] + ctrl_len) + { + elem->remove_frame = TRUE; + TRACE_0_INFO("Primitive in TX exceeds N201-U: marked to remove"); + } + } + + /* + * If frame is marked to remove, do it here + */ + if (elem->remove_frame == TRUE) + { + if (elem->prim_type EQ PRIM_DATA) + { + PFREE (*grlc_data_req); + TRACE_0_INFO("GRLC_DATA_REQ removed from TX queue"); + } + else + { + PFREE (*grlc_unitdata_req); + TRACE_0_INFO("GRLC_UNITDATA_REQ removed from TX queue"); + } + + *prim_type = PRIM_REMOVED; + } + + /* + * Remove TX queue entry management element + */ + MFREE (elem); + + /* + * Check if service queue space should be tracked (at the moment only + * for service UITX and ITX, due to flow control to this service). + */ + if (*rx_service EQ SERVICE_UITX) + { + /* + * Increment the UITX space counter for the SAPI of the primitive + * to indicate that the primitive has been stored in queue. + */ + if (*prim_type EQ PRIM_DATA) + { + llc_data->tx.queue_counter_uitx[UIMAP(*sapi)]++; + } + else /* PRIM_UNITDATA */ + { + llc_data->tx.queue_counter_uitx[UIMAP(*sapi)]++; + } + } + else if (*rx_service EQ SERVICE_ITX) + { + /* + * Increment the ITX space counter for the SAPI of the primitive + * to indicate that the primitive has been stored in queue. + */ + llc_data->tx.queue_counter_itx[IMAP(*sapi)]++; + } + } + + return; +} /* tx_get_next_frame() */ + + +/* ++------------------------------------------------------------------------------ +| Function : tx_get_first_data_frame ++------------------------------------------------------------------------------ +| Description : This procedure finds the first GRLC_DATA_REQ primitive in the +| local transmit queue and stores its queue element in the +| parameter element, if any. The primitive (element) stays in +| the queue. If no GRLC_DATA_REQ primitive is found in the queue, +| no element is stored in element, but the value NULL. +| +| Parameters : elem - must be a valid pointer to a pointer to a +| TX queue element +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void tx_get_first_data_frame (T_TX_QUEUE **elem) +{ + TRACE_FUNCTION( "tx_get_first_data_frame" ); + + /* + * Check the local transmit queue until a GRLC_DATA_REQ is found or the end + * of the queue has been reached. In the latter case, *elem is automatically + * set to NULL. + */ + for (*elem = llc_data->tx.queue; *elem NEQ NULL; *elem = (*elem)->next) + { + /* + * Check if primitive is a GRLC_DATA_REQ primitive. + */ + if ((*elem)->prim_type EQ PRIM_DATA) + { + break; + } + } + + return; +} /* tx_get_first_data_frame() */ + + +/* ++------------------------------------------------------------------------------ +| Function : tx_remove_data_frames ++------------------------------------------------------------------------------ +| Description : This procedure removes all PRIM_DATA for given SAPI and service +| from TX queue. If an element is removed and +| +| Parameters : service - service which requests to delete its primitives +| sapi - the sapi of the primitives to delete +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void tx_remove_data_frames (T_SERVICE service, T_SAPI sapi) +{ + T_TX_QUEUE *elem; + T_TX_QUEUE **find = &llc_data->tx.queue; + BOOL elem_removed = FALSE; + + TRACE_FUNCTION( "tx_remove_data_frames" ); + + while (*find NEQ NULL) + { + /* + * Let elem point to queue element + */ + elem = *find; + + /* + * Check if primitive is a GRLC_DATA_REQ primitive and + * check the sapi of the queue element + */ + if ((elem->prim_type EQ PRIM_DATA) AND + (elem->ph_sapi EQ sapi) AND + (elem->rx_service EQ service) ) + { + elem_removed = TRUE; + + /* + * Remove found element from queue (set member next of element before + * the found element to the element behind the found element and thus + * skip the found element). + */ + *find = (*find)->next; + + /* + * Check if we have a valid pointer to a primitive + */ + if ((elem->primitive NEQ (ULONG)NULL)) + { + PFREE ((T_GRLC_DATA_REQ *)elem->primitive); + + TRACE_0_INFO("TX queue element and primitive removed"); + } + else + { + /* + * Primitive is in use at CCI. + * It is no problem if the corresponding primitive to this entry + * returns from CCI, because the reference number will not be found + * and the primitive data will then be freed. + */ + TRACE_0_INFO("In use TX queue element removed"); + } + + /* + * Remove TX queue entry management element. + */ + MFREE (elem); + + /* + * Check if service queue space should be tracked (at the moment only + * for service UITX and ITX, due to flow control to this service). + * In this case increment the space counter for the SAPI of the + * primitive to indicate that the primitive has been stored in queue. + */ + if (service EQ SERVICE_UITX) + { + llc_data->tx.queue_counter_uitx[UIMAP(sapi)]++; + } + else if (service EQ SERVICE_ITX) + { + llc_data->tx.queue_counter_itx[IMAP(sapi)]++; + } + } + else + { + /* + * Point to the next queue element pointer + */ + find = &((*find)->next); + } + } + + /* + * Now check, if a ready indication must be send must be send to the + * requesting service (if at least one elem was removed, send one). + * Currently only service UITX and ITX are requesting a signal. + */ + if (elem_removed) + { + SWITCH_LLC (sapi); + + if (service EQ SERVICE_UITX) + { + sig_tx_uitx_ready_ind(); + } + else if (service EQ SERVICE_ITX) + { + sig_tx_itx_ready_ind(); + } + } + + return; +} /* tx_remove_data_frames() */ +