FreeCalypso > hg > fc-selenite
view src/g23m-gprs/llc/llc_up.c @ 196:5f3544fc0308
AT@SPENH brought over from Magnetite
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 24 May 2020 19:46:18 +0000 |
parents | d393cd9bb723 |
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 | functions to handles the incoming primitives as described in | the SDL-documentation (U-statemachine) +----------------------------------------------------------------------------- */ #ifndef LLC_UP_C #define LLC_UP_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_uf.h" /* to get local U functions */ #include "llc_ul.h" /* to get local U labels */ #include "llc_t200s.h" /* to get signal interface to T200 */ #include "llc_txs.h" /* to get signal interface to TX */ #include "llc_llmes.h" /* to get signal interface to LLME */ /*==== CONST ================================================================*/ /*==== LOCAL VARS ===========================================================*/ /*==== PRIVATE FUNCTIONS ====================================================*/ /*==== PUBLIC FUNCTIONS =====================================================*/ /* +------------------------------------------------------------------------------ | Function : u_ll_establish_req +------------------------------------------------------------------------------ | Description : Handles the primitive LL_ESTABLISH_REQ | | Parameters : *ll_establish_req - Ptr to primitive payload | +------------------------------------------------------------------------------ */ GLOBAL void u_ll_establish_req ( T_LL_ESTABLISH_REQ *ll_establish_req ) { int bytelen; TRACE_FUNCTION( "ll_establish_req" ); SWITCH_LLC (ll_establish_req->sapi); TRACE_2_PARA("s:%d xid-len:%d", ll_establish_req->sapi, BYTELEN(ll_establish_req->sdu.l_buf) ); /* * Set TLLI for current transaction. */ llc_data->u->current_tlli = llc_data->tlli_new; if (llc_data->u->ll_xid_resp_pending EQ TRUE) { PFREE (ll_establish_req); TRACE_0_INFO( "LL_ESTABLISH_REQ ignored due to LL_XID_IND collision" ); return; } switch (GET_STATE(U)) { case U_ADM: /* * store Layer-3 XID negotiation parameters, free * LL_ESTABLISH_REQ, set retransmission counter to 0 * and remember to CNF the establishment afterwards */ /* * The layer_3 xid is valid any time, even it is a * zero lenght sdu. In this case we have to include * an empty l3 xid information field. */ llc_data->requested_l3_xid->valid = TRUE; bytelen = BYTELEN( ll_establish_req->sdu.l_buf); bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN; memcpy( llc_data->requested_l3_xid->value, &(ll_establish_req->sdu.buf[ll_establish_req->sdu.o_buf >> 3]), bytelen ); llc_data->requested_l3_xid->length = bytelen; PFREE (ll_establish_req); llc_data->u->retransmission_counter = 0; /* * Send LL_ESTABLISH_CNF after successful establishment. */ llc_data->u->ind_cnf_establishment = CNF_ESTABLISHMENT; SET_STATE (U, U_LOCAL_ESTABLISHMENT); /* * send SABM (w/ Layer 3 XID parameters), start T200 */ u_send_sabm (); break; case U_LOCAL_ESTABLISHMENT: /* * XID Negotiation of layer-3 parameters not supported in * this case. */ PFREE (ll_establish_req); /* * Send LL_ESTABLISH_CNF after successful establishment. */ llc_data->u->ind_cnf_establishment = CNF_ESTABLISHMENT; break; case U_ABM: /* * store Layer-3 XID negotiation parameters, free * LL_ESTABLISH_REQ, set retransmission counter to 0 * and remember to CNF the establishment afterwards */ /* * The layer_3 xid is valid any time, even it is a * zero lenght sdu. In this case we have to include * an empty l3 xid information field. */ llc_data->requested_l3_xid->valid = TRUE; bytelen = BYTELEN( ll_establish_req->sdu.l_buf); bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN; memcpy( llc_data->requested_l3_xid->value, &(ll_establish_req->sdu.buf[ll_establish_req->sdu.o_buf >> 3]), bytelen ); llc_data->requested_l3_xid->length = bytelen; PFREE (ll_establish_req); llc_data->u->retransmission_counter = 0; /* * Send LL_ESTABLISH_CNF after successful establishment. */ llc_data->u->ind_cnf_establishment = CNF_ESTABLISHMENT; SET_STATE (U, U_LOCAL_ESTABLISHMENT); sig_u_llme_abmrel_ind(); u_send_llgmm_status_ind (LLGMM_ERRCS_L3_REEST); /* * send SABM (w/ Layer 3 XID parameters), start T200 */ u_send_sabm (); break; case U_ESTABLISH_RES_PENDING: case U_REMOTE_ESTABLISHMENT: PFREE (ll_establish_req); TRACE_0_INFO( "LL_ESTABLISH_REQ ignored due to collision" ); break; default: PFREE (ll_establish_req); TRACE_ERROR( "LL_ESTABLISH_REQ unexpected" ); break; } } /* u_ll_establish_req() */ /* +------------------------------------------------------------------------------ | Function : u_ll_establish_res +------------------------------------------------------------------------------ | Description : Handles the primitive LL_ESTABLISH_RES | | Parameters : *ll_establish_res - Ptr to primitive payload | +------------------------------------------------------------------------------ */ GLOBAL void u_ll_establish_res ( T_LL_ESTABLISH_RES *ll_establish_res ) { int bytelen; TRACE_FUNCTION( "ll_establish_res" ); SWITCH_LLC (ll_establish_res->sapi); switch (GET_STATE(U)) { case U_ESTABLISH_RES_PENDING: case U_REMOTE_ESTABLISHMENT: if (ll_establish_res->xid_valid == TRUE) { bytelen = BYTELEN( ll_establish_res->sdu.l_buf); TRACE_2_PARA("s:%d xid-len:%d", ll_establish_res->sapi, bytelen ); bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN; memcpy( llc_data->requested_l3_xid->value, &(ll_establish_res->sdu.buf[ll_establish_res->sdu.o_buf >> 3]), bytelen ); llc_data->requested_l3_xid->length = bytelen; llc_data->requested_l3_xid->valid = TRUE; } else { TRACE_1_PARA("s:%d", ll_establish_res->sapi ); llc_data->requested_l3_xid->valid = FALSE; } PFREE (ll_establish_res); if (GET_STATE(U) == U_REMOTE_ESTABLISHMENT) { /* * Send UA response with F bit set to 1 and if valid XID */ u_send_ua (1, TRUE); } SET_STATE (U, U_ABM); sig_u_t200_stop_req(); /* * <R.LLC.ABMEST_I.A.012> * vs. <R.LLC.ABMEST_I.A.015> */ sig_u_llme_abmest_ind(); break; default: TRACE_1_PARA("s:%d", ll_establish_res->sapi ); PFREE (ll_establish_res); TRACE_ERROR( "LL_ESTABLISH_RES unexpected" ); break; } } /* u_ll_establish_res() */ /* +------------------------------------------------------------------------------ | Function : u_ll_release_req +------------------------------------------------------------------------------ | Description : Handles the primitive LL_RELEASE_REQ | | Parameters : *ll_release_req - Ptr to primitive payload | +------------------------------------------------------------------------------ */ GLOBAL void u_ll_release_req ( T_LL_RELEASE_REQ *ll_release_req ) { TRACE_FUNCTION( "ll_release_req" ); SWITCH_LLC (ll_release_req->sapi); TRACE_1_PARA("s:%d", ll_release_req->sapi ); /* * Set TLLI for current transaction. */ llc_data->u->current_tlli = llc_data->tlli_new; switch (GET_STATE(U)) { case U_TLLI_UNASSIGNED: case U_ADM: /* * We are already released. Send anytime a LL_RELEASE_CNF to * SNDCP to make it more stable. */ { PPASS (ll_release_req, ll_release_cnf, LL_RELEASE_CNF); TRACE_0_INFO("LL_RELEASE_REQ not necessary"); TRACE_1_OUT_PARA("s:%d", ll_release_cnf->sapi); PSEND (hCommSNDCP, ll_release_cnf); } break; case U_ABM: sig_u_llme_abmrel_ind(); /* * No break. */ case U_ESTABLISH_RES_PENDING: if (ll_release_req->local EQ LL_REL_LOCAL) { /* * Send LL_RELEASE_CNF to SNDCP. */ PPASS (ll_release_req, ll_release_cnf, LL_RELEASE_CNF); TRACE_1_OUT_PARA("s:%d", ll_release_cnf->sapi); PSEND (hCommSNDCP, ll_release_cnf); SET_STATE (U, U_ADM); sig_u_t200_stop_req(); } else /* LL_REL_NOTLOCAL */ { PFREE (ll_release_req); llc_data->u->retransmission_counter = 0; SET_STATE (U, U_LOCAL_RELEASE); /* * Send GRLC_DATA_REQ (DISC), start T200. */ u_send_disc(); } break; case U_REMOTE_ESTABLISHMENT: /* * We are currently waiting for a LL_ESTABLISH_RSP. But * because SNDCP want's us to release the connection, we * do so and switch back to ADM operation. */ SET_STATE (U, U_ADM); if (ll_release_req->local NEQ LL_REL_LOCAL) { /* * Send DM response with F bit set to 1 */ llc_data->u->retransmission_counter = 0; u_send_dm (1); } sig_u_t200_stop_req(); { PPASS (ll_release_req, ll_release_cnf, LL_RELEASE_CNF); TRACE_1_OUT_PARA("s:%d", ll_release_cnf->sapi); PSEND (hCommSNDCP, ll_release_cnf); } break; case U_LOCAL_ESTABLISHMENT: if (ll_release_req->local EQ LL_REL_LOCAL) { /* * Stop all running procedures. The peer will do the same. * Send the LL_RELEASE_CNF to SNDCP. */ PPASS (ll_release_req, ll_release_cnf, LL_RELEASE_CNF); TRACE_1_OUT_PARA("s:%d", ll_release_cnf->sapi); PSEND (hCommSNDCP, ll_release_cnf); SET_STATE (U, U_ADM); /* * NOTE: The peer may have sent an UA or DM before being released * locally itselve. If we get an UA in state ADM we have to * send an status indication to GMM. This seems to be ok (ANS). * If not, we have to wait until T200 timeout, but this is 40s * on SAPI 11 per default. A unexpected DM response will be * ignored in state ADM and therefore no problem. */ sig_u_t200_stop_req(); } else /* LL_REL_NOTLOCAL */ { /* * We have just sent an SABM to our peer. The release request has to * be stored and handled later: * 1. after timeout of T200 don't restart timer and send rel cnf * 2. after receive DM send rel cnf * 3. after receive of an UA send DISC and after get UA send rel cnf */ llc_data->u->release_requested = TRUE; /* * Clear flag after sending an release confirmation or indication. */ PFREE (ll_release_req); TRACE_0_INFO("Release request stored"); } break; case U_LOCAL_RELEASE: /* * release will indicated later */ TRACE_0_INFO("LL_RELEASE_REQ already received"); PFREE (ll_release_req); break; default: PFREE (ll_release_req); TRACE_ERROR( "LL_RELEASE_REQ unexpected" ); break; } } /* u_ll_release_req() */ /* +------------------------------------------------------------------------------ | Function : u_ll_xid_req +------------------------------------------------------------------------------ | Description : Handles the primitive LL_XID_REQ | | Parameters : *ll_xid_req - Ptr to primitive payload | +------------------------------------------------------------------------------ */ GLOBAL void u_ll_xid_req ( T_LL_XID_REQ *ll_xid_req ) { int bytelen; TRACE_FUNCTION( "u_ll_xid_req" ); SWITCH_LLC (ll_xid_req->sapi); TRACE_2_PARA("s:%d xid-len:%d", ll_xid_req->sapi, BYTELEN(ll_xid_req->sdu.l_buf) ); if (llc_data->u->ll_xid_resp_pending EQ TRUE) { PFREE (ll_xid_req); TRACE_0_INFO( "LL_XID_REQ ignored due to LL_XID_IND collision" ); return; } switch (GET_STATE(U)) { case U_ABM: case U_ADM: /* * Copy L3-XID parameter to requested_xid * and if currently no cmd frame outstanding, * send XID command frame */ bytelen = BYTELEN( ll_xid_req->sdu.l_buf); bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN; memcpy( llc_data->requested_l3_xid->value, &(ll_xid_req->sdu.buf[ll_xid_req->sdu.o_buf >> 3]), bytelen ); llc_data->requested_l3_xid->length = bytelen; llc_data->requested_l3_xid->valid = TRUE; PFREE (ll_xid_req); if (llc_data->sapi->pbit_outstanding == FALSE) { /* * No frame with pbit set to 1 currently * outstanding, send XID comand */ llc_data->u->retransmission_counter = 0; u_tag_xid_parameters(MS_COMMAND, FALSE); u_send_xid (MS_COMMAND); } /* SET_STATE (U, SAME_STATE); */ break; case U_ESTABLISH_RES_PENDING: case U_REMOTE_ESTABLISHMENT: PFREE (ll_xid_req); TRACE_0_INFO( "LL_XID_REQ ignored due to collision" ); break; default: /* * XID only supported in states ADM + ABM */ PFREE (ll_xid_req); TRACE_ERROR( "LL_XID_REQ unexpected" ); break; } } /* u_ll_xid_req() */ /* +------------------------------------------------------------------------------ | Function : u_ll_xid_res +------------------------------------------------------------------------------ | Description : Handles the primitive LL_XID_RES | | Parameters : *ll_xid_res - Ptr to primitive payload | +------------------------------------------------------------------------------ */ GLOBAL void u_ll_xid_res ( T_LL_XID_RES *ll_xid_res ) { int bytelen; TRACE_FUNCTION( "ll_xid_res" ); SWITCH_LLC (ll_xid_res->sapi); TRACE_2_PARA("s:%d xid-len:%d", ll_xid_res->sapi, BYTELEN(ll_xid_res->sdu.l_buf) ); llc_data->u->ll_xid_resp_pending = FALSE; switch (GET_STATE(U)) { case U_ABM: case U_ADM: /* * Copy L3-XID parameter to requested_xid * and send XID response frame */ bytelen = BYTELEN( ll_xid_res->sdu.l_buf); bytelen = (bytelen < LLC_MAX_L3_XID_LEN ) ? bytelen : LLC_MAX_L3_XID_LEN; memcpy( llc_data->requested_l3_xid->value, &(ll_xid_res->sdu.buf[ll_xid_res->sdu.o_buf >> 3]), bytelen ); llc_data->requested_l3_xid->length = bytelen; llc_data->requested_l3_xid->valid = TRUE; PFREE (ll_xid_res); u_tag_xid_parameters(MS_RESPONSE, FALSE); u_send_xid (MS_RESPONSE); /* SET_STATE (U, SAME_STATE); */ break; default: /* * XID only supported in states ADM + ABM */ PFREE (ll_xid_res); TRACE_ERROR( "LL_XID_RES unexpected" ); break; } } /* u_ll_xid_res() */