FreeCalypso > hg > fc-tourmaline
view src/g23m-gprs/llc/llc_rxf.c @ 62:089c1882788c
AT%CBC extended to report Ichg
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 22 Oct 2020 22:37:31 +0000 |
parents | fa8dc04885d8 |
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 (RX-statemachine) +----------------------------------------------------------------------------- */ #ifndef LLC_RXF_C #define LLC_RXF_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_rxf.h" /* to get local defines */ #include "llc_rxp.h" /* to get the function rx_cci_decipher_cnf */ #include "llc_f.h" /* to get global functions, e.g. llc_generate_input */ #ifndef TI_PS_OP_CIPH_DRIVER #include "cci_fbsf.h" /* to get functional interface */ #endif /*==== CONST ================================================================*/ /*==== LOCAL VARS ===========================================================*/ /*==== PRIVATE FUNCTIONS ====================================================*/ #ifndef CF_FAST_EXEC GLOBAL UBYTE rx_get_desc_octet (T_desc_list *desc_list, USHORT offset, UBYTE *data_ptr); #endif /* CF_FAST_EXEC */ /*==== PUBLIC FUNCTIONS =====================================================*/ /* +------------------------------------------------------------------------------ | Function : rx_init +------------------------------------------------------------------------------ | Description : This procedure initialises all necessary variables of | receive_pdu. | | Parameters : | +------------------------------------------------------------------------------ */ #ifndef CF_FAST_EXEC GLOBAL void rx_init (void) { TRACE_FUNCTION( "rx_init" ); /* * Initialise service RX with state TLLI_UNASSIGNED. */ INIT_STATE (RX, RX_TLLI_UNASSIGNED); return; } /* rx_init() */ #endif /* CF_FAST_EXEC */ /* +------------------------------------------------------------------------------ | Function : rx_analyse_ctrl_field +------------------------------------------------------------------------------ | Description : This procedure analyses the received LLC frame control field | and sets frame_type according to the frame type (U, UI, I/S). | protected_mode is set according to the protected mode of the | frame (U and I/S always protected, UI depends on setting of | PM bit). The type of protected_mode is the same as in | CCI_DECIPHER_REQ. ns is set to N(S) for I frames, N(U) for | UI frames, or an undefined value for S and U frames. ciphering | is set to TRUE if the frame is ciphered (U never, I/S always, | UI depends on setting of E bit), otherwise to FALSE. frame_ok | indicates if the frame contains enough octets to contain a | known control field (i.e. all necessary information is | accessible, not the control field is complete!). | | Parameters : grlc_unitdata_ind - a valid pointer to a GRLC_UNITDATA_IND | primitive | frame_type - a valid pointer to a T_PDU_TYPE variable | protected_mode - a valid pointer to a UBYTE variable | sapi - a valid pointer to a UBYTE variable | ns - a valid pointer to a T_FRAME_NUM variable | ciphering - a valid pointer to a BOOL variable | header_size - a valid pointer to a USHORT variable | frame_ok - a valid pointer to a BOOL variable | +------------------------------------------------------------------------------ */ #ifndef CF_FAST_EXEC GLOBAL void rx_analyse_ctrl_field (T_GRLC_UNITDATA_IND *grlc_unitdata_ind, T_PDU_TYPE *frame_type, UBYTE *protected_mode, UBYTE *sapi, T_FRAME_NUM *ns, BOOL *ciphering, USHORT *header_size, BOOL *frame_ok) { UBYTE first_octet; UBYTE sec_octet; UBYTE command_octet; UBYTE sack_k_octet; TRACE_FUNCTION( "rx_analyse_ctrl_field" ); /* * Check if the frame contains enough octets to access the first octet of * the control field to find out the type of the frame. */ if (grlc_unitdata_ind->desc_list.list_len < CTRL_MIN_OCTETS) { *frame_ok = FALSE; return; } /* * Assume initially that the frame is ok. */ *frame_ok = TRUE; /* * Set first_octet to the value of the first frame octet (offset 0), which * is the address field. */ rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 0, &first_octet); *sapi = first_octet & 0x0F; /* * Set sec_octet to the value of the second frame octet (offset 1), which * is the first octet of the control field. */ rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 1, &sec_octet); /* * Determine frame_type, along with ns, protected_mode, and ciphering, * depending on the frame type. */ if ((sec_octet & I_FRAME_MASK) EQ I_FRAME_ID) { /* * I frame, protected, ciphered, at least 4 octets required to access all * requested information (1 Address, 3 Control). */ *frame_type = I_FRAME; *protected_mode = CCI_PM_PROTECTED; *ciphering = TRUE; /* * Check if the frame contains enough octets to access the complete * I frame control field. */ if (grlc_unitdata_ind->desc_list.list_len < I_CTRL_MIN_OCTETS) { *frame_ok = FALSE; return; } /* * Determine the header_size */ *header_size = I_CTRL_MIN_OCTETS; /* * Add bytes in case of SACK-Bitmap (add K+1). Therefore get at first * the command octet (offset 3). In case of an SACK, get next the k * octet (offset 4) and add the additional size. */ rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 3, &command_octet); if ( (command_octet & 0x03) == I_FRAME_SACK ) { *header_size += 1; /* k octet */ if (grlc_unitdata_ind->desc_list.list_len < *header_size) { *frame_ok = FALSE; return; } rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 4, &sack_k_octet); *header_size += (sack_k_octet & 0x1F); /* bitmap size */ if (grlc_unitdata_ind->desc_list.list_len < *header_size) { *frame_ok = FALSE; return; } } /* * Extract N(S) and store it in ns. */ *ns = (((T_FRAME_NUM) rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 1, NULL)) & 0x1F) << 4; *ns |= (((T_FRAME_NUM) rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 2, NULL)) >> 4); } else if ((sec_octet & S_FRAME_MASK) EQ S_FRAME_ID) { /* * S frame, protected, not ciphered. No N(S) present, only N(R). */ *frame_type = S_FRAME; *protected_mode = CCI_PM_PROTECTED; *ciphering = FALSE; *header_size = S_CTRL_MIN_OCTETS; /* not necessary to add bytes in case of SACK - value is not used */ } else if ((sec_octet & UI_FRAME_MASK) EQ UI_FRAME_ID) { /* * UI frame, at least 3 octets required to access all requested * information (1 Address, 2 Control). */ *frame_type = UI_FRAME; /* * Check if the frame contains enough octets to access the complete * UI frame control field. */ if (grlc_unitdata_ind->desc_list.list_len < UI_CTRL_MIN_OCTETS) { *frame_ok = FALSE; return; } /* * Extract protected mode setting of frame (PM bit). */ if (rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 2, NULL) & 0x01) { *protected_mode = CCI_PM_PROTECTED; } else { *protected_mode = CCI_PM_UNPROTECTED; } /* * Extract ciphering setting of frame (E bit). */ if (rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 2, NULL) & 0x02) { *ciphering = TRUE; } else { *ciphering = FALSE; } *header_size = UI_CTRL_MIN_OCTETS; /* * Extract N(U) and store it in ns. */ *ns = (((T_FRAME_NUM) rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 1, NULL)) & 0x07) << 6; *ns |= (((T_FRAME_NUM) rx_get_desc_octet (&grlc_unitdata_ind->desc_list, 2, NULL)) >> 2); } else if ((sec_octet & U_FRAME_MASK) EQ U_FRAME_ID) { /* * U frame, protected, not ciphered. No N(S) present. */ *frame_type = U_FRAME; *protected_mode = CCI_PM_PROTECTED; *ciphering = FALSE; *header_size = U_CTRL_MIN_OCTETS; } return; } /* rx_analyse_ctrl_field() */ #endif /* CF_FAST_EXEC */ /* +------------------------------------------------------------------------------ | Function : rx_decipher_req +------------------------------------------------------------------------------ | Description : Handles the function rx_decipher_req. This functions sets the | ciphering parameters and calls the deciphering driver function. | | Parameters : | +------------------------------------------------------------------------------ */ #ifndef CF_FAST_EXEC GLOBAL void rx_decipher_req (T_CCI_DECIPHER_REQ *decipher_req) { 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; U16 cnt = 0; TRACE_FUNCTION( "rx_decipher_req" ); #ifdef LLC_TRACE_CIPHERING TRACE_EVENT("DOWNLINK CIPHERED DATA"); llc_trace_desc_list(&decipher_req->desc_list); #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_dl_data_to_list(decipher_req, &in_data_list); /* * Set ciphering parameters */ cipher_req_parms.gprs_parameters.pm = decipher_req->pm; cipher_req_parms.gprs_parameters.header_size = decipher_req->header_size; cipher_req_parms.gprs_parameters.ciphering_input = decipher_req->ciphering_input; cipher_req_parms.gprs_parameters.threshold = 0; init_cipher_req_parms.direction = CIPH_DOWNLINK_DIR; init_cipher_req_parms.algo = decipher_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] = decipher_req->kc.key[i]; } { /* Use GRLC_DATA_REQ instead of CCI_CIPHER_CNF to avoid PPASS in LLC*/ PALLOC_SDU (ll_unitdata_ind, LL_UNITDATA_IND, (USHORT)((decipher_req->desc_list.list_len*8) - FCS_SIZE_BITS)); ll_unitdata_ind->sdu.o_buf = 0; ll_unitdata_ind->sdu.l_buf = 0; out_data.buf = (U32)(&ll_unitdata_ind->sdu.buf[ll_unitdata_ind->sdu.o_buf >> 3]); /* * Initialize ciphering driver and decipher 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" DECIPHER_CNF to LLC */ ll_unitdata_ind->sdu.l_buf = out_data.len * 8; ll_unitdata_ind->tlli = decipher_req->reference1; ll_unitdata_ind->cipher = (UBYTE)decipher_req->reference2; if (status == CIPH_CIPH_PASS){ ll_unitdata_ind->sapi = CCI_FCS_PASSED; } else { ll_unitdata_ind->sapi = CCI_FCS_FAILED; } #ifdef LLC_TRACE_CIPHERING TRACE_EVENT("DOWNLINK DECIPHERED DATA"); llc_trace_sdu(&ll_unitdata_ind->sdu); #endif rx_cci_decipher_cnf(ll_unitdata_ind); } /* * Free in_data array from in_data_list allocated in llc_copy_dl_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; } /* * Free descriptors from the deipher_req->desc_list */ if (decipher_req != NULL) { T_desc *desc = (T_desc *)decipher_req->desc_list.first; T_desc *next_desc; while (desc NEQ NULL){ next_desc = (T_desc *)desc->next; MFREE (desc); desc = next_desc; /* increase freed partitions counter */ cnt++; } MFREE(decipher_req); decipher_req = NULL; } llc_data->fbs.cci_freed_partition +=cnt; /* trace number of freed partitions */ if(llc_data->fbs.cci_info_trace){ TRACE_EVENT_P2("INFO CCI: freed partitions %ld, total=%ld", cnt,llc_data->fbs.cci_freed_partition); } } /* rx_decipher_req */ #endif /* +------------------------------------------------------------------------------ | Function : rx_send_decipher_req +------------------------------------------------------------------------------ | Description : This procedure allocates the CCI_DECIPHER_REQ primitive, fills | in all necessary parameters and sends the primitive to CCI. | | Parameters : grlc_unitdata_ind - a valid pointer to a GRLC_UNITDATA_IND | primitive | frame_type - indicates (un)acknowledged operation mode | protected_mode - pm setting for CCI_DECIPHER_REQ | ns - N(S)/N(U) for deciphering, otherwise | undefined value | header_size - size of header bytes (not ciphered bytes) | ciphering - indicates deciphering (TRUE/FALSE) | +------------------------------------------------------------------------------ */ #ifndef CF_FAST_EXEC GLOBAL void rx_send_decipher_req (T_GRLC_UNITDATA_IND *grlc_unitdata_ind, T_PDU_TYPE frame_type, UBYTE protected_mode, T_FRAME_NUM ns, USHORT header_size, BOOL ciphering) { ULONG oc; TRACE_FUNCTION ("rx_send_decipher_req"); { /* * No need to PPASS GRLC_xDATA_IND, because desc_list contains a pointer * which can be simply copied. */ T_CCI_DECIPHER_REQ *cci_decipher_req; MALLOC(cci_decipher_req, sizeof(T_CCI_DECIPHER_REQ)); /* * Requires rx_analyse_ctrl_field() to set a correct CCI value. */ cci_decipher_req->pm = protected_mode; if (ciphering EQ TRUE) { cci_decipher_req->reference2 = LL_CIPHER_ON; /* re-use of reference is ok */ cci_decipher_req->ciphering_algorithm = llc_data->ciphering_algorithm; memcpy (&cci_decipher_req->kc, &llc_data->kc, sizeof(T_kc)); /* * Calculate the OC which is valid for this ns. This could be the * current OC or OC + 1 in case of an modulo overflow of ns */ switch (frame_type) { case I_FRAME: case S_FRAME: if (ns >= llc_data->sapi->vr) oc = llc_data->sapi->oc_i_rx; else oc = llc_data->sapi->oc_i_rx + (MAX_SEQUENCE_NUMBER+1); break; default: if (ns >= llc_data->sapi->vur) oc = llc_data->sapi->oc_ui_rx; else oc = llc_data->sapi->oc_ui_rx + (MAX_SEQUENCE_NUMBER+1); break; } llc_generate_input (llc_data->current_sapi, frame_type, ns, &cci_decipher_req->ciphering_input, oc); cci_decipher_req->direction = CCI_DIRECTION_DOWNLINK; } else /* ciphering EQ FALSE */ { cci_decipher_req->reference2 = LL_CIPHER_OFF; cci_decipher_req->ciphering_algorithm = CCI_CIPHER_NO_ALGORITHM; } cci_decipher_req->header_size = header_size; /* * TLLI must be stored somewhere */ cci_decipher_req->reference1 = grlc_unitdata_ind->tlli; cci_decipher_req->desc_list = grlc_unitdata_ind->desc_list; /* TRACE_EVENT ("CCI thread not available, using functional interface"); */ rx_decipher_req(cci_decipher_req); } return; } /* rx_send_decipher_req() */ #endif /* CF_FAST_EXEC */ /* +------------------------------------------------------------------------------ | Function : rx_interpret_frame +------------------------------------------------------------------------------ | Description : This procedure analyses the LLC header and checksum of the | given frame (U, UI, or I) and sets sapi, pdu_type, command, | cr_bit, pf_bit, nr, and ns accordingly. The FCS field is not | included in frame, it has already been stripped off. frame_ok | is set to TRUE if the frame fulfils the following requirements: | known PDU type, valid length, valid PD bit, valid SAPI. | frame_rej indicates a frame rejection condition if any bit of | W4-W1 is set. If a frame is rejected, frame_rej_ctrl_length | indicates the length of the control field. If this length | could not be determined, frame_rej_ctrl_length is set to the | number of control field octets of the frame. | | Parameters : frame - contains the frame to be analysed, must be | a valid pointer | sapi - will be set to the SAPI of the frame, must be | a valid pointer | pdu_type - will be set to the PDU type of the frame, must be | a valid pointer | command - will be set to the command (I/S, U) of the frame | (if available), must be a valid pointer | cr_bit - will be set to the C/R bit of the frame, must be | a valid pointer | pf_bit - will be set to the P/F bit of the frame (if | available), must be a valid pointer | nr - will be set to N(R) / N(U) of the frame (if | available), must be a valid pointer | ns - will be set to N(S) of the frame (if available), | must be a valid pointer | frame_ok - TRUE if the frame is ok, else FALSE, must be | a valid pointer | frame_rej - indicates a frame rejection condition, must be | a valid pointer | frame_rej_ctrl_length - number of octets in the rejected | control field, must be a valid pointer | +------------------------------------------------------------------------------ */ /*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \ !defined(REL99) || defined(LL_2to1) */ GLOBAL void rx_interpret_frame (T_sdu *frame, UBYTE *sapi, T_PDU_TYPE *pdu_type, T_COMMAND *command, T_BIT *cr_bit, T_BIT *pf_bit, T_FRAME_NUM *nr, T_FRAME_NUM *ns, BOOL *frame_ok, UBYTE *frame_rej, USHORT *frame_rej_ctrl_length, UBYTE cipher) { USHORT min_length = 0; /* minimum required frame length */ BOOL check_length; /* check/ignore length at the end */ TRACE_FUNCTION( "rx_interpret_frame" ); /* * Preset variables with suspected success, control field length is not * yet known, so assume complete frame length. */ *frame_ok = TRUE; *frame_rej = FRAME_NOT_REJ; *frame_rej_ctrl_length = frame->l_buf/8 - 1; /* * Frame length is selectively activated, depending on frame type, command, * etc. Ignore frame length per default. */ check_length = FALSE; /* * Check if the frame contains enough octets to access the first octet of * the control field to find out the type of the frame. */ if (frame->l_buf/8 < CTRL_MIN_OCTETS) { *frame_ok = FALSE; return; } /* * Check if PD bit is set to 0. If it is not, the frame is invalid. * <R.LLC.XCEPTION.A.001> */ if ((frame->buf[frame->o_buf/8] & 0x80) != 0x00) { *frame_ok = FALSE; return; } /* * Extract C/R bit. */ *cr_bit = (frame->buf[frame->o_buf/8] & 0x40) >> 6; /* * Extract SAPI and check if the frame contains a reserved SAPI. * <R.LLC.XCEPTION.A.001> */ *sapi = frame->buf[frame->o_buf/8] & 0x0F; switch (*sapi) /* !!!!! constants or function/macro to determine invalid sapis */ { case 0: case 2: case 4: case 6: case 8: case 10: case 12: case 13: case 14: case 15: { *frame_ok = FALSE; return; } } /* * Determine the PDU type of the frame, along with the minimum length * required for this PDU type to constitute a complete frame. * Additionally, extract available variables for each PDU type. */ if ((frame->buf[(frame->o_buf/8)+1] & I_FRAME_MASK) EQ I_FRAME_ID) { /* * I frame, at least 5 octets (1 Address, 3 Control, 1(++) * Information, no FCS) */ *pdu_type = I_FRAME; min_length = I_FRAME_MIN_OCTETS_WITHOUT_FCS; *frame_rej_ctrl_length = I_CTRL_OCTETS; /* * Extract A bit (stored in P/F bit) */ *pf_bit = (frame->buf[(frame->o_buf/8)+1] & 0x40) >> 6; /* * Check if the frame contains enough octets to access the complete * I frame control field. */ if (frame->l_buf/8 < I_CTRL_MIN_OCTETS) { *frame_ok = FALSE; return; } /* * Extract N(S), N(R) */ *ns = (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+1] & 0x1F) << 4; *ns |= (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+2] >> 4); *nr = (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+2] & 0x07) << 6; *nr |= (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+3] >> 2); /* * Determine the command of the I frame (S1 & S2 bits) */ switch (frame->buf[(frame->o_buf/8)+3] & 0x03) { case I_FRAME_RR: TRACE_4_PARA("I-RR s:%d len:%d nr:%d ns:%d", *sapi, BYTELEN(frame->l_buf), *nr, *ns); *command = I_RR; break; case I_FRAME_ACK: TRACE_4_PARA("I-ACK s:%d len:%d nr:%d ns:%d", *sapi, BYTELEN(frame->l_buf), *nr, *ns); *command = I_ACK; break; case I_FRAME_RNR: TRACE_4_PARA("I-RNR s:%d len:%d nr:%d ns:%d", *sapi, BYTELEN(frame->l_buf), *nr, *ns); *command = I_RNR; break; case I_FRAME_SACK: TRACE_4_PARA("I-SACK s:%d len:%d nr:%d ns:%d", *sapi, BYTELEN(frame->l_buf), *nr, *ns); *command = I_SACK; /* * Check if the frame contains enough octets to access the complete * I frame SACK control field. K is at octet I_CTRL_MIN_OCTETS + 1 * and there must be at least K+1 octets within the bitmap. Therefore * the frame must contain a minimum of I_CTRL_MIN_OCTETS+2. */ if (frame->l_buf/8 < I_CTRL_MIN_OCTETS+2) { *frame_ok = FALSE; return; } /* * min_length is being modified to be more accurate for SACK frames, * according to the Bitmap Length Indicator K in * frame->buf[(frame->o_buf/8)+4]. */ min_length += (frame->buf[(frame->o_buf/8)+4] & 0x1F) + 1; check_length = TRUE; break; default: /* * Frame rejection condition due to receipt of a command or * response field that is undefined or not implemented (set * W3 bit to 1). * <R.LLC.XCEPTION.A.002> */ *frame_ok = FALSE; *frame_rej = FRAME_REJ_W3; return; } } else if ((frame->buf[(frame->o_buf/8)+1] & S_FRAME_MASK) EQ S_FRAME_ID) { /* * S frame, fixed 3 octets (1 Address, 2 Control, 0 Information, no FCS) */ *pdu_type = S_FRAME; min_length = S_FRAME_MIN_OCTETS_WITHOUT_FCS; *frame_rej_ctrl_length = S_CTRL_OCTETS; /* * Extract A bit (stored in P/F bit) */ *pf_bit = (frame->buf[(frame->o_buf/8)+1] & 0x20) >> 5; /* * Check if the frame contains enough octets to access the complete * S frame control field. */ if (frame->l_buf/8 < S_CTRL_MIN_OCTETS) { *frame_ok = FALSE; *frame_rej = FRAME_REJ_W1; *frame_rej_ctrl_length = frame->l_buf/8 - 1; return; } /* * Extract N(R) */ *nr = (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+1] & 0x07) << 6; *nr |= (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+2] >> 2); /* * Determine the command of the S frame (S1 & S2 bits) */ switch (frame->buf[(frame->o_buf/8)+2] & 0x03) { case I_FRAME_RR: TRACE_2_PARA("S-RR s:%d nr:%d", *sapi, *nr); *command = I_RR; check_length = TRUE; break; case I_FRAME_ACK: TRACE_2_PARA("S-ACK s:%d nr:%d", *sapi, *nr); *command = I_ACK; check_length = TRUE; break; case I_FRAME_RNR: TRACE_2_PARA("S-RNR s:%d nr:%d", *sapi, *nr); *command = I_RNR; check_length = TRUE; break; case I_FRAME_SACK: TRACE_2_PARA("S-SACK s:%d nr:%d", *sapi, *nr); *command = I_SACK; /* * min_length is being modified to be more accurate for SACK frames. * The S frame SACK format adds a number of up to 32 octets to the * control field. */ min_length += S_FRAME_SACK_MIN_CTRL_OCTETS; check_length = FALSE; break; default: /* * Frame rejection condition due to receipt of a command or * response field that is undefined or not implemented (set * W3 bit to 1). * <R.LLC.XCEPTION.A.002> */ *frame_ok = FALSE; *frame_rej = FRAME_REJ_W3; return; } } else if ((frame->buf[(frame->o_buf/8)+1] & UI_FRAME_MASK) EQ UI_FRAME_ID) { /* * UI frame, at least 3 octets (1 Address, 2 Control, 0(++) * Information, no FCS) */ *pdu_type = UI_FRAME; min_length = UI_FRAME_MIN_OCTETS_WITHOUT_FCS; *frame_rej_ctrl_length = UI_CTRL_OCTETS; /* * Check if the frame contains enough octets to access the complete * UI frame control field. */ if (frame->l_buf/8 < UI_CTRL_MIN_OCTETS) { *frame_ok = FALSE; return; } /* * Extract N(U) (is stored in N(R)) */ *nr = (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+1] & 0x07) << 6; *nr |= (T_FRAME_NUM)(frame->buf[(frame->o_buf/8)+2] >> 2); TRACE_4_PARA("UI s:%d len:%d nr:%d c:%d", *sapi, BYTELEN(frame->l_buf), *nr, cipher); } else if ((frame->buf[(frame->o_buf/8)+1] & U_FRAME_MASK) EQ U_FRAME_ID) { /* * U frame, at least 2 octets (1 Address, 1 Control, 0(++) * Information, no FCS) */ *pdu_type = U_FRAME; min_length = U_FRAME_MIN_OCTETS_WITHOUT_FCS; *frame_rej_ctrl_length = U_CTRL_OCTETS; /* * Extract P/F bit */ *pf_bit = (frame->buf[(frame->o_buf/8)+1] & 0x10) >> 4; /* * Check if the frame contains enough octets to access the complete * U frame control field. * NOTE: * This check could be omitted, because the U frame control field size * is only one octet. */ if (frame->l_buf/8 < U_CTRL_MIN_OCTETS) { *frame_ok = FALSE; *frame_rej = FRAME_REJ_W1; return; } /* * Determine the command of the U frame (M4, M3, M2, M1). * Adjust the minimum length of the frame, if possible. */ switch (frame->buf[(frame->o_buf/8)+1] & 0x0F) { case U_FRAME_DM: TRACE_1_PARA("DM s:%d", *sapi); *command = U_DM; /* * No information field is permitted. */ check_length = TRUE; break; case U_FRAME_DISC: TRACE_1_PARA("DISC s:%d", *sapi); *command = U_DISC; /* * No information field is permitted. */ check_length = TRUE; break; case U_FRAME_UA: TRACE_2_PARA("UA s:%d len:%d", *sapi, BYTELEN(frame->l_buf)); *command = U_UA; /* * No knowledge if an information field is permitted, because * this is only the case when UA is the response to SABM. */ break; case U_FRAME_SABM: TRACE_2_PARA("SABM s:%d len:%d", *sapi, BYTELEN(frame->l_buf)); *command = U_SABM; /* * An information field is permitted, containing XID * parameters. Therefore the size of the information field * is not (yet) known. */ break; case U_FRAME_FRMR: TRACE_1_PARA("FRMR s:%d", *sapi); *command = U_FRMR; /* * FRMR response contains an information field of 10 octets. * <R.LLC.XCEPTION.A.008> */ min_length += U_FRAME_FRMR_INFO_OCTETS; check_length = TRUE; break; case U_FRAME_XID: if( *cr_bit == SGSN_COMMAND ) { TRACE_2_PARA("XID REQ s:%d len:%d", *sapi, BYTELEN(frame->l_buf)); } else { TRACE_2_PARA("XID RSP s:%d len:%d", *sapi, BYTELEN(frame->l_buf)); } *command = U_XID; /* * An information field is required, containing XID * parameters. Therefore the size of the information field * is not (yet) known. */ break; default: TRACE_0_INFO("Not supported U frame received"); /* * Frame rejection condition due to receipt of a command or * response field that is undefined or not implemented (set * W3 bit to 1). * <R.LLC.XCEPTION.A.002> */ *frame_ok = FALSE; *frame_rej = FRAME_REJ_W3; return; } } /* * Determine if it is requested to check the frame length exactly * (check_length EQ TRUE), or just to check the minimum frame length * (check_length EQ FALSE). */ if (check_length AND (frame->l_buf/8 NEQ min_length)) { /* * Actual length of frame doesn't correspond with computed length. */ *frame_ok = FALSE; /* * Check if frame rejection condition occured: S or U frame with * incorrect length (= W1 + W3 bits). frame_rej_ctrl_length has already * been set above to the correct control field length. * <R.LLC.XCEPTION.A.002>, <R.LLC.XCEPTION.A.010> */ if ((*pdu_type EQ S_FRAME) OR (*pdu_type EQ U_FRAME)) { *frame_rej = FRAME_REJ_W1 | FRAME_REJ_W3; } return; } else if (frame->l_buf/8 < min_length) { /* * Frame doesn't contain enough octets to include the address field, * control field, information field, and FCS field necessary to constitute * a complete frame according to the PDU type. * <R.LLC.XCEPTION.A.001> */ *frame_ok = FALSE; return; } return; } /* rx_interpret_frame() */ /* #endif */ /* CF_FAST_EXEC || _SIMULATION_ */ /* +------------------------------------------------------------------------------ | Function : rx_strip_llc_header +------------------------------------------------------------------------------ | Description : This procedure strips the LLC header field off of the sdu | so that the sdu contains only the remaining L3-PDU. | | Parameters : sdu - contains the SDU (frame), must be a valid pointer | pdu_type - contains the PDU type of the frame, must be | a valid PDU type | command - contains the command (I/S, U) of the frame, must be | a valid command for the given PDU type | +------------------------------------------------------------------------------ */ #ifndef CF_FAST_EXEC GLOBAL void rx_strip_llc_header (T_sdu *sdu, T_PDU_TYPE pdu_type, T_COMMAND command) { UBYTE header_len = 0; TRACE_FUNCTION ("rx_strip_llc_header"); switch (pdu_type) { case I_FRAME: /* * I frame 4 octets. Leave SACK Bitmap in PDU, will be stripped later! * (1 Address, 3Control). */ header_len = I_CTRL_MIN_OCTETS; break; case S_FRAME: /* * S frame 3 octets. Leave SACK Bitmap in PDU, will be stripped later! * (1 Address, 2(+32 max) Control). */ header_len = S_CTRL_MIN_OCTETS; break; case UI_FRAME: /* * UI frame, 3 octets (1 Address, 2 Control). */ header_len = UI_CTRL_MIN_OCTETS; break; case U_FRAME: /* * U frame, 2 octets (1 Address, 1 Control). */ header_len = U_CTRL_MIN_OCTETS; break; default: TRACE_ERROR ("Unknown PDU type"); break; } /* * Adjust the beginning of the PDU using the determined header_len. */ sdu->o_buf += header_len * 8; /* * Adjust the length of the PDU by the size of the header field. */ sdu->l_buf -= header_len * 8; return; } /* rx_strip_llc_header() */ #endif /* CF_FAST_EXEC */ /* +------------------------------------------------------------------------------ | Function : rx_get_desc_octet +------------------------------------------------------------------------------ | Description : This procedure maps the given linear offset to a descriptor | list and returns the value of the octet at this offset. If | offset is too large for descriptor list, 0x00 is returned. | Each descriptor in descriptor list is evaluated until the | requested offset is reached. The resulting octet value is | written to the referenced parameter data_ptr (if not set to | NULL), and is additionally returned. | | Parameters : desc_list - a valid pointer to a valid descriptor list | offset - linear octet offset, beginning with 0 | data_ptr - a valid pointer to be set to the resulting octet | value, or NULL | +------------------------------------------------------------------------------ */ #ifndef CF_FAST_EXEC GLOBAL UBYTE rx_get_desc_octet (T_desc_list *desc_list, USHORT offset, UBYTE *data_ptr) { T_desc *desc; UBYTE *desc_data; /* local pointer to data octet */ /* * Check if offset is contained in descriptor list. Return 0x00 if not. */ if (offset >= desc_list->list_len) { TRACE_ERROR ("offset too large for descriptor list"); return 0x00; } /* * Search requested data with given linear offset in descriptor list. * Empty descriptors are skipped. Check for each descriptor if requested * offset is in descriptor, until it is found. */ desc = (T_desc *)desc_list->first; desc_data = NULL; do { if (offset < desc->len) { /* * Requested data is in current descriptor. Set desc_data to point to * requested octet with remaining offset (has been decremented by * already passed descriptor payload). */ /*lint -e662 Possible creation of out-of-bounds pointer */ desc_data = &(desc->buffer[offset]); } else { /* * Requested data is not in current descriptor. Remember data payload * of current descriptor as already passed. */ offset -= desc->len; } desc = (T_desc *)desc->next; } while ((desc NEQ NULL) AND (desc_data EQ NULL)); if (desc_data EQ NULL) { TRACE_ERROR ("descriptor list ended before offset found"); if (data_ptr NEQ NULL) { *data_ptr = 0; } return 0; } else { /* * Store value of found octet in data_ptr, if pointer is valid. */ if (data_ptr NEQ NULL) { /*lint -e661 Possible access of out-of-bounds pointer */ *data_ptr = *desc_data; } return *desc_data; } } /* rx_get_desc_octet() */ #endif /* CF_FAST_EXEC */