FreeCalypso > hg > fc-magnetite
view src/g23m-gprs/llc/llc_itxf.c @ 208:ab79cf3c29a5
AT-over-RVTMUX mechanism ported over to the TCS3.2 version of ACI
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Fri, 14 Oct 2016 17:15:08 +0000 |
parents | 219afcfc6250 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | 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() */