FreeCalypso > hg > fc-tourmaline
diff src/g23m-gprs/llc/llc_itxf.c @ 1:fa8dc04885d8
src/g23m-*: import from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 16 Oct 2020 06:25:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/g23m-gprs/llc/llc_itxf.c Fri Oct 16 06:25:50 2020 +0000 @@ -0,0 +1,1752 @@ +/* ++----------------------------------------------------------------------------- +| 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 (ITX-statemachine) ++----------------------------------------------------------------------------- +*/ + +#ifndef LLC_ITXF_C +#define LLC_ITXF_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 the global entity definitions */ +#include "llc_txs.h" /* to get signal interface to TX */ +#include "llc_itxt.h" /* to get signal interface to TX */ +#include "llc_llmes.h" /* to get signal interface to LLME */ +#include "llc_itxf.h" /* to get ITX local functions */ + +/*==== CONST ================================================================*/ + +/*==== LOCAL VARS ===========================================================*/ + +/*==== PRIVATE FUNCTIONS ====================================================*/ +LOCAL void itx_send_i_frame (T_ITX_I_QUEUE_ENTRY* entry, + T_ABIT_REQ_TYPE tr); + +LOCAL void itx_i_queue_get_next (T_IQ_STATUS* status, + T_ITX_I_QUEUE_ENTRY** entry, + T_ABIT_REQ_TYPE* rt); + +LOCAL void itx_i_queue_get_retr (T_IQ_STATUS* status, + T_ITX_I_QUEUE_ENTRY** entry, + T_ABIT_REQ_TYPE* rt); + +LOCAL void itx_s_queue_retrieve (BOOL* found, + T_COMMAND* sx, + T_ABIT_REQ_TYPE* rt, + T_FRAME_NUM* nr, + T_SACK_BITMAP* bm, + USHORT* bm_byte_size); + +LOCAL void itx_send_s_frame (T_COMMAND sx, + T_ABIT_REQ_TYPE rt, + T_FRAME_NUM nr, + T_SACK_BITMAP* bm, + USHORT bm_byte_size); + + +/*==== PUBLIC FUNCTIONS =====================================================*/ + + + +/* ++------------------------------------------------------------------------------ +| Function : itx_init ++------------------------------------------------------------------------------ +| Description : This procedure initialises all necessary variables of +| i_frames_tx for all SAPIs. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_init (void) +{ + UBYTE inc; + + TRACE_FUNCTION( "itx_init" ); + + /* + * Initialise all 4 SAPIs with state TLLI_UNASSIGNED. + */ + SWITCH_SERVICE (llc, itx, 0); + INIT_STATE (ITX_0, ITX_TLLI_UNASSIGNED); + + SWITCH_SERVICE (llc, itx, 1); + INIT_STATE (ITX_1, ITX_TLLI_UNASSIGNED); + + SWITCH_SERVICE (llc, itx, 2); + INIT_STATE (ITX_2, ITX_TLLI_UNASSIGNED); + + SWITCH_SERVICE (llc, itx, 3); + INIT_STATE (ITX_3, ITX_TLLI_UNASSIGNED); + + /* + * Initialise the ITX data structure + */ + for (inc = 0; inc < ITX_NUM_INC; inc++) + { + SWITCH_SERVICE (llc, itx, inc); + + /* + * Free old used resources (in case of an LLC restart): + * memory, stored primitives, running timer. + */ + itx_i_queue_clean(); + itx_s_queue_clean(); + + /* + * Init data area + */ + llc_data->itx->tx_waiting = FALSE; + llc_data->itx->buffer_was_full = FALSE; + + llc_data->itx->i_queue.first = NULL; + llc_data->itx->s_queue = NULL; + + llc_data->itx->n_pb_retr = 0; + } + + return; +} /* itx_init() */ + + +/* ++------------------------------------------------------------------------------ +| Function : itx_init_sapi ++------------------------------------------------------------------------------ +| Description : This procedure initialises all necessary variables of +| i_frames_tx for the current SAPI. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_init_sapi (void) +{ + TRACE_FUNCTION( "itx_init_sapi" ); + + llc_data->itx->buffer_was_full = FALSE; + + llc_data->itx->t201_entry = NULL; + llc_data->itx->n_pb_retr = 0; + llc_data->itx->B_tx = 0; + + return; +} /* itx_init_sapi() */ + + +/* ++------------------------------------------------------------------------------ +| Function : itx_queue_sequence_check ++------------------------------------------------------------------------------ +| Description : This procedure checks for the A bit request conditions "end of +| a sequence of transmitted I frames" +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_queue_sequence_check (T_IQ_STATUS status, + T_ITX_I_QUEUE_ENTRY* entry, + T_ABIT_REQ_TYPE* rt) +{ + TRACE_FUNCTION( "itx_queue_sequence_check" ); + + /* + * Do not overwrite rt, if it is already set + */ + if (*rt == ABIT_SET_REQ ) + { + return; + } + + /* + * Handle rt depending on status + */ + switch (status) + { + case IQ_NEW_FRAME: + /* + * If a next frame is not available, the sequence ends + */ + if (entry == NULL) + { + *rt = ABIT_SET_REQ; + } + break; + + case IQ_RETR_FRAME: + /* + * If no frame to retransmit is following, the sequence ends + */ + while (entry) + { + if (entry->status == IQ_RETR_FRAME) + { + /* + * Another one is following + */ + return; + } + entry = entry->next; + } + *rt = ABIT_SET_REQ; + break; + + default: + TRACE_ERROR("Status unexpected"); + break; + } +} + + + +/* ++------------------------------------------------------------------------------ +| Function : itx_i_queue_get_next ++------------------------------------------------------------------------------ +| Description : This procedure gets the next new frame from the I frame queue. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL void itx_i_queue_get_next (T_IQ_STATUS* status, + T_ITX_I_QUEUE_ENTRY** entry, + T_ABIT_REQ_TYPE* rt ) +{ + T_ITX_I_QUEUE_ENTRY* iq_ptr; + + TRACE_FUNCTION( "itx_i_queue_get_next" ); + + /* + * Search for a frame with type equal status + */ + iq_ptr = llc_data->itx->i_queue.first; + while (iq_ptr) + { + /* + * check if we have found the entry + */ + if (iq_ptr->status == IQ_NEW_FRAME) + { + *entry = iq_ptr; + *status = IQ_NEW_FRAME; + + /* + * check for A bit set condition + */ + itx_queue_sequence_check (IQ_NEW_FRAME, iq_ptr->next, rt); + + /* + * next one found + */ + return; + } + + iq_ptr = iq_ptr->next; + } + + /* + * We have nothing found to transmit + */ + *entry = NULL; + *status = IQ_NO_FRAME; + *rt = ABIT_NO_REQ; + +} /* itx_i_queue_get_next() */ + +/* ++------------------------------------------------------------------------------ +| Function : itx_i_queue_get_retr ++------------------------------------------------------------------------------ +| Description : This procedure gets the next frame maked for retransmission +| from the I frame queue. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL void itx_i_queue_get_retr (T_IQ_STATUS* status, + T_ITX_I_QUEUE_ENTRY** entry, + T_ABIT_REQ_TYPE* rt ) +{ + T_ITX_I_QUEUE_ENTRY* iq_ptr; + + TRACE_FUNCTION( "itx_i_queue_get_retr" ); + + /* + * Search for a frame makred for retransmission + * Retransmissions can't be stored after new frames + */ + iq_ptr = llc_data->itx->i_queue.first; + while (iq_ptr && iq_ptr->status != IQ_NEW_FRAME) + { + /* + * check if we have found the entry + */ + if (iq_ptr->status == IQ_RETR_FRAME) + { + *entry = iq_ptr; + *status = IQ_RETR_FRAME; + + /* + * check for A bit set condition + */ + itx_queue_sequence_check (IQ_RETR_FRAME, iq_ptr->next, rt); + + /* + * next one found + */ + return; + } + + iq_ptr = iq_ptr->next; + } + + /* + * We have nothing found to transmit + */ + *entry = NULL; + *status = IQ_NO_FRAME; + *rt = ABIT_NO_REQ; + +} /* itx_i_queue_get_retr () */ + + +/* ++------------------------------------------------------------------------------ +| Function : itx_send_next_frame ++------------------------------------------------------------------------------ +| Description : If LLC is not suspended and TX is ready to receive a frame, +| this procedure handles the sending of the next I/S or S frame, +| if one is availabel in the I or S queue. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_send_next_frame (T_ABIT_REQ_TYPE req) +{ + T_ITX_I_QUEUE_ENTRY* entry; + T_IQ_STATUS status; + T_ABIT_REQ_TYPE rt = ABIT_NO_REQ; + T_SACK_BITMAP bm; + T_COMMAND sx; + T_FRAME_NUM nr; + USHORT bm_byte_size; + BOOL found; + + TRACE_FUNCTION( "itx_send_next_frame" ); + + /* + * First check, if TX is ready to receive a frame + */ + if ((llc_data->itx->tx_waiting == FALSE) || (llc_data->suspended == TRUE)) + { + /* + * Label ITX_SEND_1 + */ + + return; + } + + /* + * Try to get a frame marked for retransmission from the I queue + */ + itx_i_queue_get_retr (&status, &entry, &rt); + + /* + * If we found none, try to get a new frame + */ + if (status == IQ_NO_FRAME ) + { + /* + * Try it only, if the transmit window is not full => V(S) < V(A) + k + */ + if ( FRAME_WIN_VALID(llc_data->sapi->vs, llc_data->sapi->va, *(llc_data->ku)) ) + { + itx_i_queue_get_next (&status, &entry, &rt); + } + } + + switch (status) + { + case IQ_NO_FRAME: + /* + * Label ITX_SEND_2 + */ + + /* + * No I frame to send, look for a S frame + */ + itx_s_queue_retrieve (&found, &sx, &rt, &nr, &bm, &bm_byte_size); + /* + * If an command was found, send it, else leave + */ + if (found) + { + itx_send_s_frame (sx, rt, nr, &bm, bm_byte_size); + } + break; + + case IQ_NEW_FRAME: + /* + * Set A-bit flag in case of V(S) = V(A) + k after sending + */ + if( llc_data->sapi->vs == (llc_data->sapi->va + + *(llc_data->ku) - 1) % (MAX_SEQUENCE_NUMBER+1) ) + { + rt = ABIT_SET_REQ; + } + + /* + * Set current value of V(S) and OC to the next frame and + * increment it. Must be done before calling send_i_frame + * because of possible recursion! + */ + entry->ns = llc_data->sapi->vs++; + entry->oc_i_tx = llc_data->sapi->oc_i_tx; + + /* + * Handle OC(tx) and MAX_SEQUENCE_NUMBER for acknowledged transfer. + */ + if (llc_data->sapi->vs > MAX_SEQUENCE_NUMBER) + { + llc_data->sapi->vs = 0; + llc_data->sapi->oc_i_tx += (MAX_SEQUENCE_NUMBER+1); + } + + /* + * Transmit I frame and set waiting for acknowlege + */ + itx_send_i_frame (entry, rt); + break; + + case IQ_RETR_FRAME: + /* + * Increment retransmission counter and check if + * another transmission of this frame is allowed. + */ + entry->n_retr++; + if (entry->n_retr <= *(llc_data->n200) ) + { + /* + * Retransmit frame and set waiting for acknowlege + */ + itx_send_i_frame (entry, rt); + } + else + { + /* + * Initiate re-establish + */ + sig_itx_llme_reest_ind (LLGMM_ERRCS_ACK_NO_PEER_RES_REEST); + } + break; + + default: + TRACE_ERROR ("UNEXPECTED RETURN CODE"); + break; + } + +} /* itx_send_next_frame() */ + + +/* ++------------------------------------------------------------------------------ +| Function : itx_s_queue_clean ++------------------------------------------------------------------------------ +| Description : This procedure removes all entries from the S frame queue +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_s_queue_clean (void) +{ + T_ITX_S_QUEUE_ENTRY** entry = &(llc_data->itx->s_queue); + + TRACE_FUNCTION( "itx_s_queue_clean" ); + + while (*entry) + { + /* + * get pointer to next (=first) entry + */ + T_ITX_S_QUEUE_ENTRY* current = *entry; + + /* + * remove next entry from the entry (make second to first) + */ + *entry = current->next; + + /* + * free the removed entry + */ + MFREE (current); + } +} /* itx_s_queue_clean() */ + + +/* ++------------------------------------------------------------------------------ +| Function : itx_i_queue_clean ++------------------------------------------------------------------------------ +| Description : This procedure removes all entries including the attached L3 +| data from the I-frame queue. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_i_queue_clean (void) +{ + T_ITX_I_QUEUE_ENTRY** entry = &(llc_data->itx->i_queue.first); + + TRACE_FUNCTION( "itx_i_queue_clean" ); + + while( *entry ) + { + /* + * get pointer to next (=first) entry + */ + T_ITX_I_QUEUE_ENTRY* current = *entry; + + /* + * remove next entry from the entry (make second to first) + */ + *entry = current->next; + + /* + * free L3 primitive data, if attached to the removed entry + */ + if (current->frame) + { + + /* + * Decrease attached counter. If no one is still attached + * free the primitive memory + */ + if (current->frame->attached_counter > CCI_NO_ATTACHE) + { + current->frame->attached_counter --; + + if (current->frame->attached_counter == CCI_NO_ATTACHE) + { +#ifdef LL_DESC + /* + * The descriptor contents of the primitive structure + * must be freed as well. + */ + llc_cl_desc3_free((T_desc3*)current->frame->desc_list3.first); +#endif /* LL_DESC */ + PFREE (current->frame); + } + else + { + TRACE_0_INFO("LL_DATA_REQ still attached"); + } + } + } + + /* + * free next entry + */ + MFREE (current); + } + + /* + * Adjust number of stored entries in I frame queue + */ + llc_data->itx->i_queue.entries = 0; + + /* + * Adjust I frame queue size + */ + llc_data->itx->B_tx = 0; + + /* + * If a I frame is associated with T201, also reset this + */ + TIMERSTOP (T201); + llc_data->itx->t201_entry = NULL; + +} /* itx_i_queue_clean() */ + + +/* ++------------------------------------------------------------------------------ +| Function : itx_handle_ll_ready_ind ++------------------------------------------------------------------------------ +| Description : This procedure checks if further storing of L3 data is allowed. +| If possible, a LL_READY_IND is send. +| +| Parameters : data_send - TRUE if data sent was the reason to call +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_handle_ll_ready_ind (BOOL data_send) +{ + ULONG M = *(llc_data->mu) * 16; + + TRACE_FUNCTION( "itx_handle_ll_ready_ind" ); + + /* + * If data_send was the reason to call this function, + * only send ready, if buffer was full last call. + */ + if ((data_send == TRUE) && (llc_data->itx->buffer_was_full == FALSE)) + { + /* + * Nothing to do + */ + return; + } + + /* + * Check if we already have stored more frames than current ku or if + * M - if relevant - would exceed if we would add an N201 size frame. + * If this is true set buffer_was_full to TRUE. Otherwise send out an + * LL_READY_IND. + */ + if ((llc_data->itx->i_queue.entries < *(llc_data->ku) + ITX_ADD_QUEUE_SIZE) AND + ( (M == 0) OR (*(llc_data->n201_i) <= M - llc_data->itx->B_tx) ) ) + { + PALLOC (ll_ready_ind, LL_READY_IND); + + ll_ready_ind->sapi = llc_data->current_sapi; + + TRACE_1_OUT_PARA("s:%d", ll_ready_ind->sapi); + PSEND (hCommSNDCP, ll_ready_ind); + + llc_data->itx->buffer_was_full = FALSE; + } + else + { + llc_data->itx->buffer_was_full = TRUE; + + TRACE_0_INFO("ITX buffer full"); + } +} /* itx_handle_ll_ready_ind() */ + +/* ++------------------------------------------------------------------------------ +| Function : itx_i_queue_store ++------------------------------------------------------------------------------ +| Description : This procedure tries to store the L3 data request. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_i_queue_store +( +#ifdef LL_DESC + T_LL_DESC_REQ* ll_desc_req, BOOL *result +#else + T_LL_DATA_REQ* ll_desc_req, BOOL *result +#endif +) +{ +#ifdef LL_DESC + T_desc3* desc3; +#endif + ULONG M = *(llc_data->mu) * 16; + + TRACE_FUNCTION( "itx_i_queue_store" ); + + /* + * Check, if M would exceed if we transmit this frame. + */ +#ifdef LL_DESC + if ( M == 0 || + (ULONG)(ll_desc_req->desc_list3.list_len) <= M - llc_data->itx->B_tx ) +#else + if ( M == 0 || + (ULONG)(BYTELEN(ll_desc_req->sdu.l_buf)) <= M - llc_data->itx->B_tx ) +#endif + { + /* + * Store data to the end of the queue (queue type: oldies first) + */ + T_ITX_I_QUEUE_ENTRY** entry = &(llc_data->itx->i_queue.first); + + while( *entry ) + entry = &((*entry)->next); + + MALLOC( *entry, sizeof(T_ITX_I_QUEUE_ENTRY) ); + + if( *entry ) + { + /* + * Memory successful allocated. Fill in struct entries. + */ + (*entry)->next = NULL; + (*entry)->status = IQ_NEW_FRAME; + (*entry)->n_retr = 0; + (*entry)->ns = 0; + (*entry)->frame = ll_desc_req; + + /* + * Store primitive header parameter + */ + (*entry)->ll_qos = ll_desc_req->ll_qos; + (*entry)->radio_prio = ll_desc_req->radio_prio; + (*entry)->reference = ll_desc_req->reference1; + (*entry)->seg_pos = ll_desc_req->seg_pos; + +#ifdef REL99 + /* + * Fill packet flow identifier with corrrect values if it is from one of the SNDCP SAP. + * If data request is from GMM fill PFI = LL_PFI_SIGNALING, + * If data request is from GSMS fill PFI = LL_PFI_SMS + * for all other SAPs(if sapi 2 & 8 are supported in future) set pkt_flow_id is to LL_PKT_FLOW_ID_NOT_PRES, + * until specification are clarified. + */ + switch(ll_desc_req->sapi) + { + case LL_SAPI_1: + /* + * From 24.008 & 23.060 it is interpreted that for all signalling data, a + * predefined PFI LL_PFI_SIGNALING shall be used. + */ + (*entry)->pkt_flow_id = LL_PFI_SIGNALING; + break; + + case LL_SAPI_3: + case LL_SAPI_5: + case LL_SAPI_9: + case LL_SAPI_11: + (*entry)->pkt_flow_id = (UBYTE)ll_desc_req->pkt_flow_id; + break; + + case LL_SAPI_7: + /* + * From 24.008 & 23.060 it is interpreted that for all SMS data, a + * predefined PFI LL_PFI_SMS shall be used. + */ + (*entry)->pkt_flow_id = LL_PFI_SMS; + break; + + default: + /* + * It is possible when we support llc sapi 2 and 8 are supported. + * Fill PFI valuse it LL_PKT_FLOW_ID_NOT_PRES + */ + (*entry)->pkt_flow_id = LL_PKT_FLOW_ID_NOT_PRES; + break; + } +#endif /*REL99 */ + +#ifdef LL_DESC + desc3 = (T_desc3*)ll_desc_req->desc_list3.first; + + (*entry)->offset = desc3->offset; + (*entry)->len = desc3->len; + + /* + * Increase attached counter + */ + ll_desc_req->attached_counter ++; + + /* + * Increase number of stored entries in I frame queue + */ + llc_data->itx->i_queue.entries++; + + /* + * Increase amount of stored Information in I frame queue + */ + + llc_data->itx->B_tx += (ll_desc_req->desc_list3.list_len); + +#else + (*entry)->sdu_o_buf = ll_desc_req->sdu.o_buf; + (*entry)->sdu_l_buf = ll_desc_req->sdu.l_buf; + + /* + * Increase attached counter + */ + ll_desc_req->attached_counter ++; + + /* + * Increase number of stored entries in I frame queue + */ + llc_data->itx->i_queue.entries++; + + /* + * Increase amount of stored Information in I frame queue + */ + llc_data->itx->B_tx += BYTELEN(ll_desc_req->sdu.l_buf); + +#endif /*LL_DESC */ + /* + * Store data succeded + */ + *result = TRUE; + return; + } + else + { + /* + * Out of memory + */ + TRACE_ERROR( "Out of memory in itx_i_queue_store()" ); + } + } + + *result = FALSE; + return; +} /* itx_i_queue_store() */ + + + +/* ++------------------------------------------------------------------------------ +| Function : itx_i_queue_get_ready ++------------------------------------------------------------------------------ +| Description : This procedure checks, if the next entry in the queue is +| already acknowledged. If this is true, the entry will be +| removed and the frame reference will be returned. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_i_queue_get_ready (BOOL* found, +#ifdef LL_2to1 + T_LL_reference1* reference, +#else + T_reference1* reference, +#endif + UBYTE state) +{ + T_ITX_I_QUEUE_ENTRY** entry = &(llc_data->itx->i_queue.first); + + TRACE_FUNCTION( "itx_i_queue_get_ready" ); + + /* + * The first entry is the oldest. Only this must be observed. + */ + if ((*entry) != NULL && (*entry)->status == IQ_IS_ACK_FRAME) + { + /* + * store pointer to the entry + */ + T_ITX_I_QUEUE_ENTRY* current = *entry; + + /* + * remove entry from the queue (make second to first) + */ + *entry = current->next; + + /* + * Decrease number of stored entries in I frame queue + */ + llc_data->itx->i_queue.entries--; + + if (current->frame) + { + + /* + * return original data request reference number + */ + *reference = current->reference; + + /* + * decrease amount of stored Information in I frame queue. + * Take the original value of sdu_len as it was send by L3 + */ +#ifdef LL_DESC + if (llc_data->itx->B_tx >= (ULONG)(current->len)) + { + llc_data->itx->B_tx -= (ULONG)(current->len); +#else + if (llc_data->itx->B_tx >= (ULONG)(BYTELEN(current->sdu_l_buf))) + { + llc_data->itx->B_tx -= (ULONG)(BYTELEN(current->sdu_l_buf)); +#endif + } + else + { + llc_data->itx->B_tx = 0; + TRACE_0_INFO("Unexpected SDU bytelen handled"); + } + + /* + * decrease attached counter. If no one is still attached + * free the primitive memory + */ + if (current->frame->attached_counter > CCI_NO_ATTACHE) + { + current->frame->attached_counter --; + + if (current->frame->attached_counter == CCI_NO_ATTACHE) + { +#ifdef LL_DESC + llc_cl_desc3_free((T_desc3*)current->frame->desc_list3.first); +#endif /* LL_DESC */ + PFREE (current->frame); + } + else + { + TRACE_0_INFO("LL_DATA_REQ still attached"); + } + } + } + else + { + *found = FALSE; + TRACE_0_INFO("No LL_DATA_REQ attached to queue entry"); + return; + } + + /* + * if the retrieved I frame is associated with T201, reset this + */ + if (current == llc_data->itx->t201_entry) + { + if (state != ITX_ABM_PEER_BUSY) + { + /* + * In this state the timer handles other stuff + */ + TIMERSTOP (T201); + } + + llc_data->itx->t201_entry = NULL; + } + + /* + * free retrieved entry + */ + MFREE (current); + + *found = TRUE; + } + else + { + *found = FALSE; + } +} /* itx_i_queue_get_ready() */ + + + +/* ++------------------------------------------------------------------------------ +| Function : itx_i_queue_set_status ++------------------------------------------------------------------------------ +| Description : This procedure sets the acknowledge flag to the frame send with +| N equal to num. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_i_queue_set_status (T_IQ_STATUS status, T_FRAME_NUM num) +{ + T_ITX_I_QUEUE_ENTRY* entry = llc_data->itx->i_queue.first; + + TRACE_FUNCTION( "itx_i_queue_set_status" ); + + while (entry) + { + /* + * check if we have found the entry + */ + if (entry->ns == num ) + { + /* + * found it - set ack and leave + */ + entry->status = status; + return; + } + + /* + * goto next entry + */ + entry = entry->next; + } +} /* itx_i_queue_set_status() */ + + +/* ++----------------------------------------------------------------------------- +| Function : itx_s_queue_store ++------------------------------------------------------------------------------ +| Description : This procedure stores the command to the end of the S queue +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +GLOBAL void itx_s_queue_store (T_COMMAND command, + T_ABIT_REQ_TYPE req_type, + T_FRAME_NUM nr, + T_SACK_BITMAP* bitmap) +{ + T_ITX_S_QUEUE_ENTRY** entry = &(llc_data->itx->s_queue); + + TRACE_FUNCTION( "itx_s_queue_store" ); + + /* + * find the end + */ + while( *entry ) + entry = &((*entry)->next); + + /* + * allocate memory + */ + MALLOC( *entry, sizeof(T_ITX_S_QUEUE_ENTRY) ); + + if( *entry ) + { + /* + * Memory successful allocated. Fill in struct entries. + */ + (*entry)->next = NULL; + (*entry)->sx = command; + (*entry)->rt = req_type; + (*entry)->nr = nr; + + /* + * Copy SACK bitmap + */ + if (bitmap) + { + (*entry)->bitmap = *bitmap; + } + } + else + { + /* + * Out of memory + */ + TRACE_ERROR( "Out of memory in itx_i_queue_store()" ); + } +} /* itx_s_queue_store() */ + + +/* ++------------------------------------------------------------------------------ +| Function : itx_s_queue_retrieve ++------------------------------------------------------------------------------ +| Description : This procedure returns the first entry and removes it from the +| the queue or, if not available returns a RR command with found +| set to false. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL void itx_s_queue_retrieve (BOOL* found, + T_COMMAND* sx, + T_ABIT_REQ_TYPE* rt, + T_FRAME_NUM* nr, + T_SACK_BITMAP* bm, + USHORT* bm_byte_size) +{ + int i; + + T_ITX_S_QUEUE_ENTRY** entry = &(llc_data->itx->s_queue); + + TRACE_FUNCTION( "itx_s_queue_retrieve" ); + + /* + * Take the next entry, if available + */ + if (*entry != NULL) + { + /* + * Store pointer to the entry + */ + T_ITX_S_QUEUE_ENTRY* current = *entry; + + /* + * Remove entry from the queue (make second to first) + */ + *entry = current->next; + + *sx = current->sx; + *rt = current->rt; + *nr = current->nr; + *bm = current->bitmap; + + /* + * Free retrieved entry + */ + MFREE (current); + + *found = TRUE; + + /* + * Special handling for SACK command + */ + if(*sx == I_SACK) + { + /* + * Calculate bitmap size + */ + for(i = S_FRAME_SACK_MAX_CTRL_OCTETS-1; i >= 0; i--) + { + if( bm->data[i] != 0) + { + /* + * Return bm size in bits + */ + *bm_byte_size = i+1; + return; + } + } + } + + /* + * No valid bitmap found, return + */ + *bm_byte_size = 0; + return; + } + else + { + /* + * Set default return values + */ + *found = FALSE; + *sx = I_RR; + *nr = llc_data->sapi->vr; + *rt = ABIT_NO_REQ; + *bm_byte_size = 0; + } +} /* itx_s_queue_retrieve () */ + + +/* ++------------------------------------------------------------------------------ +| Function : itx_send_i_frame ++------------------------------------------------------------------------------ +| Description : This procedure gets the next supervisor information to send +| and build together with the I frame to transmit the final +| (expect ciphering and FSC, which will be done by TX) LLC frame. +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL void itx_send_i_frame (T_ITX_I_QUEUE_ENTRY* entry, + T_ABIT_REQ_TYPE a_req) +{ +#ifdef LL_DESC + T_desc_list3* desc_list3; + T_desc3* desc3; + U8* desc_buf; +#else + T_sdu* sdu; +#endif + T_COMMAND sx; + T_ABIT_REQ_TYPE rt; + T_SACK_BITMAP bm; + T_FRAME_NUM nr; + USHORT bm_byte_size; + USHORT header_size; + USHORT offset; + BOOL found; + + TRACE_FUNCTION( "itx_send_i_frame" ); + +#ifdef LL_DESC + if (entry && entry->frame) + { + PALLOC(ll_unitdesc_req, LL_UNITDESC_REQ); + + ll_unitdesc_req->attached_counter = entry->frame->attached_counter; + ll_unitdesc_req->desc_list3 = entry->frame->desc_list3; + + /* + * Restore original primitive header parameter of the frame. + */ + ll_unitdesc_req->sapi = llc_data->current_sapi; + ll_unitdesc_req->tlli = llc_data->tlli_new; + ll_unitdesc_req->ll_qos = entry->ll_qos; + ll_unitdesc_req->cipher = LL_CIPHER_ON; + ll_unitdesc_req->radio_prio = entry->radio_prio; + ll_unitdesc_req->seg_pos = entry->seg_pos; +#ifdef REL99 + ll_unitdesc_req->pkt_flow_id = entry->pkt_flow_id; +#endif /* REL99 */ + + desc_list3 = &(ll_unitdesc_req->desc_list3); + + desc3 = (T_desc3*)(desc_list3->first); + + /* + * Restore original desc3 offset and length + */ + desc3->offset = entry->offset; + desc3->len = entry->len; + +#else + if (entry && entry->frame) + { + PPASS (entry->frame, ll_unitdesc_req, LL_UNITDATA_REQ); + + /* + * Restore original primitive header parameter of the frame. + */ + ll_unitdesc_req->sapi = llc_data->current_sapi; + ll_unitdesc_req->tlli = llc_data->tlli_new; + ll_unitdesc_req->ll_qos = entry->ll_qos; + ll_unitdesc_req->cipher = LL_CIPHER_ON; + ll_unitdesc_req->radio_prio = entry->radio_prio; + ll_unitdesc_req->seg_pos = entry->seg_pos; +#ifdef REL99 + ll_unitdesc_req->pkt_flow_id = entry->pkt_flow_id; +#endif /* REL99 */ + + sdu = &(ll_unitdesc_req->sdu); + + /* + * Restore original SDU offset and length + */ + sdu->o_buf = entry->sdu_o_buf; + sdu->l_buf = entry->sdu_l_buf; +#endif + + + /* + * Get next S-frame. Take the returned RR if not found = FALSE. + */ + itx_s_queue_retrieve (&found, &sx, &rt, &nr, &bm, &bm_byte_size); + + /* + * Overwrite A-bit flag request, if neccessary + */ + if (a_req == ABIT_SET_REQ) + { + rt = ABIT_SET_REQ; + } + +#ifndef LL_DESC + /* + * header_size is 4 octets + 1 byte SACK header and the size of + * SACK bitmap. The SDU length equal bytes more than the original values. + */ + if (bm_byte_size > 0) + { + header_size = I_CTRL_MIN_OCTETS + 1 + bm_byte_size; + sdu->o_buf -= header_size * 8; + sdu->l_buf += header_size * 8; + } + else + { + header_size = I_CTRL_MIN_OCTETS; + sdu->o_buf -= header_size * 8; + sdu->l_buf += header_size * 8; + } + + if (entry->sdu_o_buf < header_size * 8) + { + TRACE_ERROR ("ERROR: SDU offset not big enough"); + /* + * Now try to give stack a chance to continue + */ + sdu->o_buf = 0; + } + + offset = sdu->o_buf/8; + + /* + * Build LLC Header: + * First insert address field (PD and C/R bit are always 0) + */ + sdu->buf[offset++] = llc_data->current_sapi; + + /* + * Insert 1st octet of control field: + * Set A bit and 5 most significant bits of N(S) + */ + if (rt == ABIT_SET_REQ) + { + sdu->buf[offset++] = 0x40 | (UBYTE)(entry->ns >> 4); + } + else + { + sdu->buf[offset++] = (UBYTE)(entry->ns >> 4); + } + + /* + * Insert 2nd octet of control field: + * 4 least significant bits of N(S) and 3 most significant bits of N(R) + */ + sdu->buf[offset++] = (UBYTE)(((entry->ns << 4) & 0xF0) | (nr >> 6)); + + /* + * Insert 3nd octet of control field: + * 6 least significant bits of N(R) and the supervisory function bits + */ + sdu->buf[offset++] = (UBYTE)(((nr << 2) & 0xFC) | sx); + + /* + * Special SACK handling + */ + if (sx == I_SACK && bm_byte_size != 0) + { + USHORT i; + + /* + * Insert 1 SACK octet: k - number of SACK bytes + */ + sdu->buf[offset++] = (UBYTE)bm_byte_size; + + /* + * Insert SACK bitmap + */ + for (i = 0; i < bm_byte_size; i++) + { + sdu->buf[offset++] = bm.data[i]; + } + } + + /* + * Set frame to waiting for ack + */ + entry->status = IQ_W4ACK_FRAME; +#else /* LL_DESC*/ + + /* + * header_size is 4 octets + 1 byte SACK header and the size of + * SACK bitmap. The SDU length equal bytes more than the original values. + */ + if (bm_byte_size > 0) + { + header_size = I_CTRL_MIN_OCTETS + 1 + bm_byte_size; + desc3->offset -= header_size; + desc3->len += header_size; + desc_list3->list_len += header_size; + } + else + { + header_size = I_CTRL_MIN_OCTETS; + desc3->offset -= header_size; + desc3->len += header_size; + desc_list3->list_len += header_size; + } + + if (entry->offset < header_size) + { + TRACE_ERROR ("ERROR: SDU offset not big enough"); + /* + * Now try to give stack a chance to continue + */ + desc3->offset = 0; + } + + offset = desc3->offset; + desc_buf = (UBYTE*)desc3->buffer; + + if(!desc_buf) + { + TRACE_ERROR("desc_buf is NULLPTR !!!"); + return; + } + + /* + * Build LLC Header: + * First insert address field (PD and C/R bit are always 0) + */ + desc_buf[offset++] = llc_data->current_sapi; + + /* + * Insert 1st octet of control field: + * Set A bit and 5 most significant bits of N(S) + */ + if (rt == ABIT_SET_REQ) + { + desc_buf[offset++] = 0x40 | (UBYTE)(entry->ns >> 4); + } + else + { + desc_buf[offset++] = (UBYTE)(entry->ns >> 4); + } + + /* + * Insert 2nd octet of control field: + * 4 least significant bits of N(S) and 3 most significant bits of N(R) + */ + desc_buf[offset++] = (UBYTE)(((entry->ns << 4) & 0xF0) | (nr >> 6)); + + /* + * Insert 3nd octet of control field: + * 6 least significant bits of N(R) and the supervisory function bits + */ + desc_buf[offset++] = (UBYTE)(((nr << 2) & 0xFC) | sx); + + /* + * Special SACK handling + */ + if (sx == I_SACK && bm_byte_size != 0) + { + USHORT i; + + /* + * Insert 1 SACK octet: k - number of SACK bytes + */ + desc_buf[offset++] = (UBYTE)bm_byte_size; + + /* + * Insert SACK bitmap + */ + for (i = 0; i < bm_byte_size; i++) + { + desc_buf[offset++] = bm.data[i]; + } + } + + /* + * Set frame to waiting for ack + */ + entry->status = IQ_W4ACK_FRAME; + +#endif /* LL_DESC */ +#ifdef TRACE_EVE + { + static char* sf[] = { "RR", "ACK", "RNR", "SACK" }; + + if(sx <= 3) + { + TRACE_4_INFO("Next I-Frame %s NS:%d NR:%d A:%d", sf[sx], entry->ns, nr, rt); + } + } +#endif + + /* + * reset TX ready flag + */ + llc_data->itx->tx_waiting = FALSE; + + /* + * If A bit was set, associate T201 with the transmitted I frame + * and start T201 + */ + if (rt == ABIT_SET_REQ) + { + llc_data->itx->t201_entry = entry; + TIMERSTART(T201, llc_data->t200->length); + } + + /* + * Now send the frame to TX ( do this as last statement - recursion possible) + */ + sig_itx_tx_data_req( ll_unitdesc_req, I_FRAME, entry->ns, GRLC_DTACS_DEF, header_size, + entry->oc_i_tx); + } +} /* itx_send_i_frame() */ + + +/* ++------------------------------------------------------------------------------ +| Function : itx_send_s_frame ++------------------------------------------------------------------------------ +| Description : This procedure sends the supervisor command to TX +| +| Parameters : +| ++------------------------------------------------------------------------------ +*/ +LOCAL void itx_send_s_frame (T_COMMAND sx, + T_ABIT_REQ_TYPE rt, + T_FRAME_NUM nr, + T_SACK_BITMAP* bm, + USHORT bm_byte_size) +{ + USHORT offset; + +#ifndef LL_DESC + T_sdu* sdu; + USHORT sdu_bitsize; +#else + T_desc3* desc3; + USHORT desc_bytesize; + U8* buf; +#endif + + TRACE_FUNCTION( "itx_send_s_frame" ); + +#ifndef LL_DESC + /* + * Calculate SDU size + */ + sdu_bitsize = (S_FRAME_MIN_OCTETS_WITHOUT_FCS * 8) + (bm_byte_size * 8); + + /* + * Build primitive and include supervisory command + */ + { + PALLOC_SDU (ll_unitdata_req, LL_UNITDATA_REQ, sdu_bitsize); + + ll_unitdata_req->sapi = llc_data->current_sapi; + ll_unitdata_req->tlli = llc_data->tlli_new; + + ll_unitdata_req->attached_counter = CCI_NO_ATTACHE; + /* + * LLC does not know the QoS profile. S frames should use + * LL_NO_REL + */ + ll_unitdesc_req->ll_qos = llc_data->cur_qos; + TRACE_EVENT_P1("peak throughput = %d",llc_data->cur_qos.peak); + + /* + * LLC signalling frames are always sent with highest priority. + */ + ll_unitdesc_req->radio_prio = llc_data->cur_radio_prio; + TRACE_EVENT_P1("radio priority = %d",llc_data->cur_radio_prio); + + +#ifdef REL99 + /* + * From 24.008 & 23.060 it is interpreted that for all signalling data, a + * predefined PFI LL_PFI_SIGNALING shall be used. + */ + ll_unitdesc_req->pkt_flow_id = llc_data->cur_pfi; + TRACE_EVENT_P1("packet flow id = %d",llc_data->cur_pfi); + +#endif /* REL99 */ + + /* + * Don't worry about L3 reference - TX will ignore it + */ + + /* + * SDU offset is 0. The SDU length is sdu_bitsize + */ + sdu = &(ll_unitdata_req->sdu); + sdu->o_buf = 0; + sdu->l_buf = sdu_bitsize; + + offset = 0; + + /* + * Build LLC Header: + * First insert address field (PD and C/R bit are always 0) + */ + sdu->buf[offset++] = llc_data->current_sapi; + + /* + * Set A bit and 3 most significant bits of N(R) + */ + if (rt == ABIT_SET_REQ) + { + /* LINTED [following sdu index fits into sdu] */ + sdu->buf[offset++] = 0xA0 | (UBYTE)(nr >> 6); + } + else + { + /* LINTED [following sdu index fits into sdu] */ + sdu->buf[offset++] = 0x80 | (UBYTE)(nr >> 6); + } + + /* + * 6 least significant bits of N(R) and the supervisory function bits + */ + { + /* LINTED [following sdu index fits into sdu] */ + sdu->buf[offset++] = (UBYTE)(((nr << 2) & 0xFC) | sx); + } + + /* + * Special SACK bitmap handling + */ + if (sx == I_SACK && bm_byte_size != 0 && bm != NULL) + { + USHORT i; + + /* + * Insert SACK bitmap + */ + for (i = 0; i < bm_byte_size; i++) + { + /* LINTED [following sdu indexes are fitting into sdu] */ + sdu->buf[offset++] = bm->data[i]; + } + } + +#ifdef TRACE_EVE + { + static char* sf[] = { "RR", "ACK", "RNR", "SACK" }; + + if(sx <= 3) + { + TRACE_3_INFO("Next S-Frame %s NR:%d A:%d", sf[sx], nr, rt); + } + } +#endif + + /* + * Reset TX ready flag (before sending because of possible recursion) + */ + llc_data->itx->tx_waiting = FALSE; + + /* + * Now send the frame to TX. header_size and oc are not used and set to zero. + */ + sig_itx_tx_data_req( ll_unitdata_req, S_FRAME, nr, GRLC_DTACS_DEF, 0, 0); + } +#else /* LL_DESC */ + + /* + * Calculate DESC size + */ + desc_bytesize = (S_FRAME_MIN_OCTETS_WITHOUT_FCS) + (bm_byte_size); + + /* + * Build primitive and include supervisory command + */ + { + PALLOC (ll_unitdesc_req, LL_UNITDESC_REQ); + + desc3 = llc_palloc_desc(desc_bytesize, 0); + + ll_unitdesc_req->desc_list3.first = (ULONG)desc3; + ll_unitdesc_req->desc_list3.list_len = desc3->len; + + ll_unitdesc_req->sapi = llc_data->current_sapi; + ll_unitdesc_req->tlli = llc_data->tlli_new; + + ll_unitdesc_req->attached_counter = CCI_NO_ATTACHE; + /* + * LLC does not know the QoS profile. S frames should use + * LL_NO_REL + */ + ll_unitdesc_req->ll_qos.peak = GRLC_PEAK_SUB; +#ifdef LL_2to1 + ll_unitdesc_req->ll_qos.relclass = PS_NO_REL; +#else + ll_unitdesc_req->ll_qos.relclass = LL_NO_REL; +#endif + + /* + * LLC signalling frames are always sent with highest priority. + */ + ll_unitdesc_req->radio_prio = GRLC_RADIO_PRIO_1; +#ifdef REL99 + /* + * From 24.008 & 23.060 it is interpreted that for all signalling data, a + * predefined PFI LL_PFI_SIGNALING shall be used. + */ + ll_unitdesc_req->pkt_flow_id = LL_PFI_SIGNALING; +#endif /* REL99 */ + /* + * Don't worry about L3 reference - TX will ignore it + */ + + /* + * SDU offset is 0. The SDU length is sdu_bitsize + */ + desc3->offset = 0; + desc3->len = desc_bytesize; + + offset = 0; + buf = (U8*)desc3->buffer; + /* + * Build LLC Header: + * First insert address field (PD and C/R bit are always 0) + */ + buf[offset++] = llc_data->current_sapi; + + /* + * Set A bit and 3 most significant bits of N(R) + */ + if (rt == ABIT_SET_REQ) + { + /* LINTED [following sdu index fits into sdu] */ + buf[offset++] = 0xA0 | (UBYTE)(nr >> 6); + } + else + { + /* LINTED [following sdu index fits into sdu] */ + buf[offset++] = 0x80 | (UBYTE)(nr >> 6); + } + + /* + * 6 least significant bits of N(R) and the supervisory function bits + */ + { + /* LINTED [following sdu index fits into sdu] */ + buf[offset++] = (UBYTE)(((nr << 2) & 0xFC) | sx); + } + + /* + * Special SACK bitmap handling + */ + if (sx == I_SACK && bm_byte_size != 0 && bm != NULL) + { + USHORT i; + + /* + * Insert SACK bitmap + */ + for (i = 0; i < bm_byte_size; i++) + { + /* LINTED [following sdu indexes are fitting into sdu] */ + buf[offset++] = bm->data[i]; + } + } + +#ifdef TRACE_EVE + { + static char* sf[] = { "RR", "ACK", "RNR", "SACK" }; + + if(sx <= 3) + { + TRACE_3_INFO("Next S-Frame %s NR:%d A:%d", sf[sx], nr, rt); + } + } +#endif + + /* + * Reset TX ready flag (before sending because of possible recursion) + */ + llc_data->itx->tx_waiting = FALSE; + + /* + * Now send the frame to TX. header_size and oc are not used and set to zero. + */ + sig_itx_tx_data_req( ll_unitdesc_req, S_FRAME, nr, GRLC_DTACS_DEF, 0, 0); + } +#endif /* LL_DESC */ +} /* itx_send_s_frame() */ + +