FreeCalypso > hg > fc-magnetite
view src/g23m-gprs/llc/llc_uf.c @ 503:0c5f61a73709
hybrid-gpf configuration created
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Mon, 25 Jun 2018 00:51:54 +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 (U-statemachine) +----------------------------------------------------------------------------- */ #ifndef LLC_UF_C #define LLC_UF_C #endif #define ENTITY_LLC /*==== INCLUDES =============================================================*/ #include <string.h> /* to get memcpy() */ #include "typedefs.h" /* to get Condat data types */ #include "vsi.h" /* to get a lot of macros */ #include "macdef.h" #include "gprs.h" #include "gsm.h" /* to get a lot of macros */ #include "cnf_llc.h" /* to get cnf-definitions */ #include "mon_llc.h" /* to get mon-definitions */ #include "prim.h" /* to get the definitions of used SAP and directions */ #include "llc.h" /* to get the global entity definitions */ #include "llc_f.h" /* to get global functions, e.g. llc_init_parameters */ #include "llc_uf.h" /* to get local XID definitions */ #include "llc_t200s.h" /* to get signal interface to T200 */ #include "llc_txs.h" /* to get signal interface to TX */ /*==== CONST ================================================================*/ /*==== LOCAL VARS ===========================================================*/ /*==== PRIVATE FUNCTIONS ====================================================*/ /*==== PUBLIC FUNCTIONS =====================================================*/ /* * CHECK_INSTANCE: * v(ariable) - variable name of parameter */ #define CHECK_INSTANCE(v) \ if (llc_data->decoded_xid.##v##.valid) \ { \ /* \ * More than one instance of the same XID parameter type is included. \ */ \ if (cr_bit EQ SGSN_COMMAND) \ { \ /* \ * XID command: Ignore all instances except the first. \ * <R.LLC.XIDNEG_R.A.014> \ */ \ continue; \ } \ else /* SGSN_RESPONSE */ \ { \ /* \ * XID response: The XID information field is regarded as invalid. \ * <R.LLC.XID_INVA.A.012> \ */ \ TRACE_0_INFO ("More than one instance of an XID-IE in RSP"); \ return FALSE; \ } \ } /* * CHECK_LENGTH_VALUE: * l(ength) - default length of parameter * c(ondition) - out-of-range value condition * v(ariable) - variable name of parameter * d(default) - default value of parameter */ #define CHECK_LENGTH_VALUE(l,c,v,d) \ if ((length NEQ l) OR (c)) \ { \ /* \ * Unsupported length or out-of-range values. \ */ \ if (cr_bit EQ SGSN_COMMAND) \ { \ /* \ * XID command: Set the value for this type according to our \ * preferences. \ * <R.LLC.XIDNEG_R.A.003> \ */ \ llc_data->decoded_xid.##v##.valid = TRUE; \ llc_data->decoded_xid.##v##.value = d; \ break; \ } \ else /* SGSN_RESPONSE */ \ { \ /* \ * XID response: The XID information field is regarded as invalid. \ * <R.LLC.XID_INVA.A.007>, <R.LLC.XID_INVA.A.009> \ */ \ TRACE_0_INFO ("Unsupported length or out-of-range values in RSP"); \ return FALSE; \ } \ } /* * CHECK_SENSE_OF_NEGOTIATION: * d(ata) - received data value to check * v(ariable) - variable name of parameter * s(ense) - sense of negotiation (XID_SENSE_UP / XID_SENSE_DOWN) */ #define CHECK_SENSE_OF_NEGOTIATION(d,v,s) \ { \ /* \ * XID response must not contain an XID parameter with a value that \ * violates the sense of negotiation. \ * <R.LLC.XID_INVA.A.008> \ */ \ if (cr_bit EQ SGSN_RESPONSE) \ { \ /* \ * First compare the value with the requested value, if there is any \ */ \ if ( (llc_data->u->requested_xid.##v##.valid) AND \ (llc_data->u->requested_xid.##v##.value s d) ) \ { \ TRACE_0_INFO ("Sense of negotiation error"); \ return FALSE; \ } \ else if( !(llc_data->u->requested_xid.##v##.valid) AND \ (*(llc_data->##v) s d) ) \ { \ /* \ * If the value was not requested but included in response, compare \ * it with the current value \ */ \ TRACE_0_INFO ("Value not requested, but sense of negotiation error"); \ return FALSE; \ } \ } \ } /* +------------------------------------------------------------------------------ | Function : u_init +------------------------------------------------------------------------------ | Description : This procedure initialises all necessary variables of u_frames | for all SAPIs. | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_init (void) { TRACE_FUNCTION( "u_init" ); /* * Initialise every incarnation of U with state TLLI_UNASSIGNED. */ SWITCH_SERVICE (llc, u, 0); INIT_STATE (U_0, U_TLLI_UNASSIGNED); SWITCH_SERVICE (llc, u, 1); INIT_STATE (U_1, U_TLLI_UNASSIGNED); SWITCH_SERVICE (llc, u, 2); INIT_STATE (U_2, U_TLLI_UNASSIGNED); SWITCH_SERVICE (llc, u, 3); INIT_STATE (U_3, U_TLLI_UNASSIGNED); SWITCH_SERVICE (llc, u, 4); INIT_STATE (U_4, U_TLLI_UNASSIGNED); SWITCH_SERVICE (llc, u, 5); INIT_STATE (U_5, U_TLLI_UNASSIGNED); return; } /* u_init() */ /* +------------------------------------------------------------------------------ | Function : u_init_sapi +------------------------------------------------------------------------------ | Description : This procedure initialises all necessary variables of u_frames | for the given SAPI after a TLLI assignment of LLC was occurred. | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_init_sapi (void) { TRACE_FUNCTION( "u_init_sapi" ); /* * Initial, no XID command is currently being sent. */ llc_data->u->xid_pending = FALSE; llc_data->u->xid_tag = 0L; llc_data->u->xid_tag_negotiate = 0L; llc_data->u->xid_tag_sent = 0L; llc_data->u->release_requested = FALSE; llc_data->u->ll_xid_resp_pending = FALSE; return; } /* u_init_sapi() */ /* +------------------------------------------------------------------------------ | Function : u_build_u_frame +------------------------------------------------------------------------------ | Description : This procedure fills the given sdu with a correct LLC frame, | containing the address field and the control field (U format). | The information field is not filled in by this procedure. | The checksum field (FCS) is also not filled in by this | procedure, it is filled in by the send_pdu service before | sending. | | Parameters : sdu - a valid pointer to an SDU, containing enough octets for | the requested command/response | cr_bit - C/R bit for the frame | sapi - a valid SAPI for unacknowledged operation | pf_bit - P/F bit for the U frame | command - a valid command/response for the U frame | +------------------------------------------------------------------------------ */ GLOBAL void u_build_u_frame ( #ifdef LL_DESC T_desc_list3 *desc_list3, #else T_sdu *sdu, #endif T_BIT cr_bit, UBYTE sapi, T_BIT pf_bit, T_COMMAND command ) { #ifdef LL_DESC T_desc3 *desc3; UBYTE *desc_buf; #endif TRACE_FUNCTION( "u_build_u_frame" ); #ifdef LL_DESC /* * Let every frame begin at the beginning. */ desc3 = (T_desc3*)desc_list3->first; desc3->offset = 0; desc_buf = (UBYTE*)desc3->buffer; /* * Fill in address and control fields. * NOTE: The values of the commands are chosen to correspond with the * defined values of the Mx bits in the control field. Therefore the given * command can be used to build the header, regardless of its actual value. */ desc_buf[0] = ((UBYTE)cr_bit << 6) | sapi; desc_buf[1] = 0xE0 | ((UBYTE)pf_bit << 4) | (UBYTE)command; /* * Determine the length of the frame, depending on the command/ * response. */ switch (command) { #ifdef REL99 case U_NULL: /* * The NULL command contains no information field. The size * of the frame is fixed. (FCS ist not yet considered in l_buf, will * be included when FCS is appended to the frame.) */ desc3->len = U_NULL_SIZE_BITS/8; break; #endif /* REL99 */ case U_DM: /* * The DM response contains no information field. The size * of the frame is fixed. (FCS ist not yet considered in l_buf, will * be included when FCS is appended to the frame.) */ desc3->len = U_DM_SIZE_BITS/8; break; case U_DISC: /* * The DISC response contains no information field. The size * of the frame is fixed. (FCS ist not yet considered in l_buf, will * be included when FCS is appended to the frame.) */ desc3->len = U_DISC_SIZE_BITS/8; break; case U_UA: /* * The UA response may contain an information field. Set only the * size of the header (address + control fields). */ desc3->len = 2; break; case U_SABM: /* * The SABM command may contain an information field. Set only the * size of the header (address + control fields). */ desc3->len = 2; break; case U_FRMR: /* * The FRMR response contains an information field of fixed size. * u_insert_frmr_information() relies on a sane value in l_buf, * therefore set only the size of the header (address + control field). */ desc3->len = 2; break; case U_XID: /* * The XID command/response contains an information field. Set only the * size of the header (address + control fields). */ desc3->len = 2; break; default: desc3->len = 0; TRACE_ERROR ("Undefined Command specified"); break; } desc_list3->list_len = desc3->len; return; #else /* * Let every frame begin at the beginning. */ sdu->o_buf = 0; /* * Fill in address and control fields. * NOTE: The values of the commands are chosen to correspond with the * defined values of the Mx bits in the control field. Therefore the given * command can be used to build the header, regardless of its actual value. */ sdu->buf[0] = ((UBYTE)cr_bit << 6) | sapi; sdu->buf[1] = 0xE0 | ((UBYTE)pf_bit << 4) | (UBYTE)command; /* * Determine the length of the frame, depending on the command/ * response. */ switch (command) { #ifdef REL99 case U_NULL: /* * The NULL command contains no information field. The size * of the frame is fixed. (FCS ist not yet considered in l_buf, will * be included when FCS is appended to the frame.) */ sdu->l_buf = U_NULL_SIZE_BITS; break; #endif /* REL99 */ case U_DM: /* * The DM response contains no information field. The size * of the frame is fixed. (FCS ist not yet considered in l_buf, will * be included when FCS is appended to the frame.) */ sdu->l_buf = U_DM_SIZE_BITS; break; case U_DISC: /* * The DISC response contains no information field. The size * of the frame is fixed. (FCS ist not yet considered in l_buf, will * be included when FCS is appended to the frame.) */ sdu->l_buf = U_DISC_SIZE_BITS; break; case U_UA: /* * The UA response may contain an information field. Set only the * size of the header (address + control fields). */ sdu->l_buf = 2*8; break; case U_SABM: /* * The SABM command may contain an information field. Set only the * size of the header (address + control fields). */ sdu->l_buf = 2*8; break; case U_FRMR: /* * The FRMR response contains an information field of fixed size. * u_insert_frmr_information() relies on a sane value in l_buf, * therefore set only the size of the header (address + control field). */ sdu->l_buf = 2*8; break; case U_XID: /* * The XID command/response contains an information field. Set only the * size of the header (address + control fields). */ sdu->l_buf = 2*8; break; default: sdu->l_buf = 0; TRACE_ERROR ("Undefined Command specified"); break; } return; #endif /* LL_DESC */ } /* u_build_u_frame() */ /* +------------------------------------------------------------------------------ | Function : u_check_xid +------------------------------------------------------------------------------ | Description : This procedure checks the XID information field that is given | in SDU. If it is invalid, rc_xid_valid is set to FALSE, | otherwise to TRUE. All XID parameters are decoded and stored | in llc_decoded_xid (global variable) if they are valid. The | parameters cr_bit and command are necessary to distinguish | between the different commands and responses. Each parameter | is checked for multiple instances, correct sense of | negotiation, and valid field length and value. | | Parameters : sdu - a valid pointer to an SDU | cr_bit - C/R bit of the frame | command - command/response of the U frame | +------------------------------------------------------------------------------ */ GLOBAL BOOL u_check_xid (T_sdu *sdu, T_BIT cr_bit, T_COMMAND command) { UBYTE *par; BOOL xl; UBYTE type; UBYTE length = 0; UBYTE *data; ULONG value; TRACE_FUNCTION( "u_check_xid" ); /* * Initialise each valid flag to FALSE. */ llc_data->decoded_xid.version.valid = FALSE; llc_data->decoded_xid.iov_ui.valid = FALSE; llc_data->decoded_xid.iov_i.valid = FALSE; llc_data->decoded_xid.t200.valid = FALSE; llc_data->decoded_xid.n200.valid = FALSE; llc_data->decoded_xid.n201_u.valid = FALSE; llc_data->decoded_xid.n201_i.valid = FALSE; llc_data->decoded_xid.md.valid = FALSE; llc_data->decoded_xid.mu.valid = FALSE; llc_data->decoded_xid.kd.valid = FALSE; llc_data->decoded_xid.ku.valid = FALSE; llc_data->decoded_xid.reset.valid = FALSE; llc_data->decoded_l3_xid.valid = FALSE; /* * Initialise par with the first XID parameter. * Process each XID parameter until the end of the list is reached: * - Check if end of list is reached (max. SDU length). * ...process XID parameter (set xl and length)... * - Increment par to point to the next XID parameter (is incremented by * (data) length plus header length). */ #ifdef TRACE_EVE { int i; int l = sdu->l_buf/8; int o = sdu->o_buf/8; vsi_o_ttrace(VSI_CALLER TC_EVENT, "XID sdu dump len:%d bytes", l); for (i=0; i<l; i+=10) { vsi_o_ttrace(VSI_CALLER TC_EVENT, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x", sdu->buf[o+i+0], sdu->buf[o+i+1], sdu->buf[o+i+2], sdu->buf[o+i+3], sdu->buf[o+i+4], sdu->buf[o+i+5], sdu->buf[o+i+6], sdu->buf[o+i+7], sdu->buf[o+i+8], sdu->buf[o+i+9]); } } #endif for (par = &(sdu->buf[sdu->o_buf/8]); par < (&(sdu->buf[sdu->o_buf/8]) + sdu->l_buf/8); par += length + (xl ? 2 : 1)) { /* * Store XL bit in boolean xl. */ xl = (*par & 0x80) > 0; /* * Store (data) length, and set data to point to the beginning * of the XID parameter data. */ if (xl) { /* * XL == 1: length is given in 8 bits. */ length = (*par & 0x03) << 6; length += (*(par+1) & 0xFC) >> 2; data = par + 2; } else { /* * XL == 0: length is given in 2 bits. */ length = *par & 0x03; data = par + 1; } if (data + length > &(sdu->buf[sdu->o_buf/8]) + sdu->l_buf/8) { /* * The XID parameter field violates the LLC frame format (exceeds given * SDU size). * <R.LLC.XID_INVA.A.001> */ return FALSE; } /* * Store type field. */ type = (*par & 0x7C) >> 2; /* * Check type and store parameter data, if any. */ switch (type) { case XID_VERSION: CHECK_INSTANCE (version); /* * XID response must not contain an XID parameter with a value that * violates the sense of negotiation. * <R.LLC.XID_INVA.A.008> */ if (cr_bit EQ SGSN_RESPONSE) { /* * First compare the value with the requested value, if there is any */ if ( (llc_data->u->requested_xid.version.valid) AND (llc_data->u->requested_xid.version.value XID_SENSE_DOWN (*data & 0x0F)) ) { return FALSE; } else if( !(llc_data->u->requested_xid.version.valid) AND llc_data->version XID_SENSE_DOWN (*data & 0x0F) ) { /* * If the value was not requested but included in response, compare * it with the current value */ return FALSE; } } /*lint -e685 Relational operator always evaluates to false*/ CHECK_LENGTH_VALUE (XID_VERSION_LEN, ((*data & 0x0F) > XID_VERSION_MAX), version, llc_data->version); /*lint +e685 Relational operator always evaluates to false*/ /* * Set version as valid and store value. */ llc_data->decoded_xid.version.valid = TRUE; llc_data->decoded_xid.version.value = *data & 0x0F; TRACE_1_INFO("XID Version:%d", llc_data->decoded_xid.version.value); break; case XID_IOV_UI: CHECK_INSTANCE (iov_ui); value = ((ULONG)*data) << 24; value += ((ULONG)*(data+1)) << 16; value += ((ULONG)*(data+2)) << 8; value += *(data+3); /*lint -e685 Relational operator always evaluates to false*/ CHECK_LENGTH_VALUE (XID_IOV_UI_LEN, (value > XID_IOV_UI_MAX), iov_ui, llc_data->iov_ui); /*lint +e685 Relational operator always evaluates to false*/ /* * Set iov_ui as valid and store value. */ llc_data->decoded_xid.iov_ui.valid = TRUE; llc_data->decoded_xid.iov_ui.value = value; TRACE_1_INFO("XID IOV-UI:0x%.8X", value); break; case XID_IOV_I: if (command EQ U_XID) { /* * IOV-I must not be contained in an XID command/response. * <R.LLC.XID_INVA.A.010>, <R.LLC.XID_PAR.A.003> */ TRACE_0_INFO("IOV-I must not be contained in an XID command/response"); return FALSE; } CHECK_INSTANCE (iov_i); value = ((ULONG)*data) << 24; value += ((ULONG)*(data+1)) << 16; value += ((ULONG)*(data+2)) << 8; value += *(data+3); /*lint -e685 Relational operator always evaluates to false*/ CHECK_LENGTH_VALUE (XID_IOV_I_LEN, (value > XID_IOV_I_MAX), iov_i, *(llc_data->iov_i)); /*lint +e685 Relational operator always evaluates to false*/ /* * Set iov_i as valid and store value. */ llc_data->decoded_xid.iov_i.valid = TRUE; llc_data->decoded_xid.iov_i.value = value; TRACE_1_INFO("XID IOV-I:0x%.8X", value); break; case XID_T200: CHECK_INSTANCE (t200); value = ((ULONG)*data) << 8; value += *(data+1); value &= 0x00000FFFL; /* * XID response must not contain an XID parameter with a value that * violates the sense of negotiation. * <R.LLC.XID_INVA.A.008> */ if (cr_bit EQ SGSN_RESPONSE) { /* * First compare the value with the requested value, if there is any */ if ( (llc_data->u->requested_xid.t200.valid) AND (llc_data->u->requested_xid.t200.value XID_SENSE_UP value) ) { TRACE_1_INFO("Value of T200:%d illegal", value); return FALSE; } else if( !(llc_data->u->requested_xid.t200.valid) AND (USHORT)INT2XID(llc_data->t200->length) XID_SENSE_UP value ) { /* * If the value was not requested but included in response, compare * it with the current value */ TRACE_1_INFO("Requested value of T200:%d illegal", value); return FALSE; } } CHECK_LENGTH_VALUE (XID_T200_LEN, ((value < XID_T200_MIN) OR (value > XID_T200_MAX)), t200, (USHORT)INT2XID(llc_data->t200->length)); /* * Set t200 as valid and store value. */ llc_data->decoded_xid.t200.valid = TRUE; llc_data->decoded_xid.t200.value = (USHORT)value; TRACE_1_INFO("XID T200:%d", llc_data->decoded_xid.t200.value); break; case XID_N200: CHECK_INSTANCE (n200); CHECK_SENSE_OF_NEGOTIATION ((*data & 0x0F), n200, XID_SENSE_UP); /*lint -e685 Relational operator always evaluates to false*/ CHECK_LENGTH_VALUE (XID_N200_LEN, (((*data & 0x0F) < XID_N200_MIN) OR ((*data & 0x0F) > XID_N200_MAX)), n200, *(llc_data->n200)); /*lint +e685 Relational operator always evaluates to false*/ /* * Set n200 as valid and store value. */ llc_data->decoded_xid.n200.valid = TRUE; llc_data->decoded_xid.n200.value = *data & 0x0F; TRACE_1_INFO("XID N200:%d", llc_data->decoded_xid.n200.value); break; case XID_N201_U: CHECK_INSTANCE (n201_u); value = ((ULONG)*data) << 8; value += *(data+1); value &= 0x000007FFL; CHECK_SENSE_OF_NEGOTIATION ((USHORT)value, n201_u, XID_SENSE_DOWN); CHECK_LENGTH_VALUE (XID_N201_U_LEN, (((USHORT)value < XID_N201_U_MIN) OR (value > XID_N201_U_MAX)), n201_u, *(llc_data->n201_u)); /* * Set n201_u as valid and store value. */ llc_data->decoded_xid.n201_u.valid = TRUE; llc_data->decoded_xid.n201_u.value = (USHORT)value; TRACE_1_INFO("XID N201-U:%d", llc_data->decoded_xid.n201_u.value); break; case XID_N201_I: CHECK_INSTANCE (n201_i); value = ((ULONG)*data) << 8; value += *(data+1); value &= 0x000007FFL; CHECK_SENSE_OF_NEGOTIATION ((USHORT)value, n201_i, XID_SENSE_DOWN); CHECK_LENGTH_VALUE (XID_N201_I_LEN, ((value < XID_N201_I_MIN) OR (value > XID_N201_I_MAX)), n201_i, *(llc_data->n201_i)); /* * Set n201_i as valid and store value. */ llc_data->decoded_xid.n201_i.valid = TRUE; llc_data->decoded_xid.n201_i.value = (USHORT)value; TRACE_1_INFO("XID N201-I:%d", llc_data->decoded_xid.n201_i.value); break; case XID_MD: CHECK_INSTANCE (md); value = ((ULONG)*data) << 8; value += *(data+1); value &= 0x00007FFFL; CHECK_SENSE_OF_NEGOTIATION ((USHORT)value, md, XID_SENSE_DOWN); CHECK_LENGTH_VALUE (XID_MD_LEN, ((value != XID_MD_OFF) AND ((value < XID_MD_MIN) OR (value > XID_MD_MAX))), md, *(llc_data->md)); /* * Set md as valid and store value. */ llc_data->decoded_xid.md.valid = TRUE; llc_data->decoded_xid.md.value = (USHORT)value; TRACE_1_INFO("XID MD:%d", llc_data->decoded_xid.md.value); break; case XID_MU: CHECK_INSTANCE (mu); value = ((ULONG)*data) << 8; value += *(data+1); value &= 0x00007FFFL; CHECK_SENSE_OF_NEGOTIATION ((USHORT)value, mu, XID_SENSE_DOWN); CHECK_LENGTH_VALUE (XID_MU_LEN, ((value != XID_MU_OFF) AND ((value < XID_MU_MIN) OR (value > XID_MU_MAX))), mu, *(llc_data->mu)); /* * Set mu as valid and store value. */ llc_data->decoded_xid.mu.valid = TRUE; llc_data->decoded_xid.mu.value = (USHORT)value; TRACE_1_INFO("XID MU:%d", llc_data->decoded_xid.mu.value); break; case XID_KD: CHECK_INSTANCE (kd); CHECK_SENSE_OF_NEGOTIATION (*data, kd, XID_SENSE_DOWN); /*lint -e685 Relational operator always evaluates to false*/ CHECK_LENGTH_VALUE (XID_KD_LEN, ((*data < XID_KD_MIN) OR (*data > XID_KD_MAX)), kd, *(llc_data->kd)); /*lint +e685 Relational operator always evaluates to false*/ /* * Set kd as valid and store value. */ llc_data->decoded_xid.kd.valid = TRUE; llc_data->decoded_xid.kd.value = *data; TRACE_1_INFO("XID KD:%d", llc_data->decoded_xid.kd.value); break; case XID_KU: CHECK_INSTANCE (ku); CHECK_SENSE_OF_NEGOTIATION (*data, ku, XID_SENSE_DOWN); /*lint -e685 Relational operator always evaluates to false*/ CHECK_LENGTH_VALUE (XID_KU_LEN, ((*data < XID_KU_MIN) OR (*data > XID_KU_MAX)), ku, *(llc_data->ku)); /*lint +e685 Relational operator always evaluates to false*/ /* * Set ku as valid and store value. */ llc_data->decoded_xid.ku.valid = TRUE; llc_data->decoded_xid.ku.value = *data; TRACE_1_INFO("XID KU:%d", llc_data->decoded_xid.ku.value); break; case XID_LAYER_3: if (llc_data->decoded_l3_xid.valid) { /* * More than one instance of the same XID parameter type is included. */ if (cr_bit EQ SGSN_COMMAND) { /* * XID command: Ignore all instances except the first. * <R.LLC.XIDNEG_R.A.014> */ continue; } else /* SGSN_RESPONSE */ { /* * XID response: The XID information field is regarded as invalid. * <R.LLC.XID_INVA.A.012> */ TRACE_0_INFO("More than one L3 parameters are included in XID response."); return FALSE; } } if ((llc_data->current_sapi NEQ LL_SAPI_3) AND (llc_data->current_sapi NEQ LL_SAPI_5) AND (llc_data->current_sapi NEQ LL_SAPI_9) AND (llc_data->current_sapi NEQ LL_SAPI_11)) { /* * Layer-3 parameters on a SAPI different from 3, 5, 9, and 11. * <R.LLC.XID_INVA.A.011> */ TRACE_0_INFO("L3 parameters on a SAPI different from 3, 5, 9, and 11."); return FALSE; } /* * Set layer_3 as valid and store Layer-3 XID parameters. */ llc_data->decoded_l3_xid.valid = TRUE; llc_data->decoded_l3_xid.length = length; memcpy (llc_data->decoded_l3_xid.value, data, length); TRACE_1_INFO("XID L3:%d bytes", length); break; case XID_RESET: if (par NEQ &(sdu->buf[sdu->o_buf/8])) { /* * Reset must be the first parameter in the XID information field. * <R.LLC.XID_INVA.A.004> */ TRACE_0_INFO("Reset must be the first XID parameter."); return FALSE; } if (cr_bit EQ SGSN_COMMAND) { if (command EQ U_SABM) { /* * SABM command: Reset is not allowed. * <R.LLC.XID_INVA.A.003> */ TRACE_0_INFO("Reset is not allowed in SABM command"); return FALSE; } } else /* SGSN_RESPONSE */ { /* * UA/XID response: Reset is not allowed. * <R.LLC.XID_INVA.A.005> */ TRACE_0_INFO("Reset is not allowed in UA/XID response"); return FALSE; } /* * Set reset as valid. */ llc_data->decoded_xid.reset.valid = TRUE; TRACE_0_INFO("XID Reset"); break; default: /* * Unrecognised type field. */ if (cr_bit EQ SGSN_COMMAND) { /* * XID command: Skip XID parameter. * <R.LLC.XIDNEG_R.A.002> */ continue; } else /* SGSN_RESPONSE */ { /* * XID response: The XID information field is regarded as invalid. * <R.LLC.XID_INVA.A.006> */ TRACE_0_INFO("Unrecognised type field in XID response."); return FALSE; } } } /* * All XID parameters have been processed, XID information field seems * to be correct. */ return TRUE; } /* u_check_xid() */ /* +------------------------------------------------------------------------------ | Function : u_eval_xid +------------------------------------------------------------------------------ | Description : This procedure evaluates the decoded XID information field in | llc_decoded_xid (global variable). If Reset is present, the | state of every incarnation in ABM is set to ADM (including | the current incarnation!), all LLC layer parameters are set | to their default values, the OCs for unack. transfer are set | to 0, and the parameter reset_received is set to TRUE. If a | command has been received (cr_bit is set to SGSN_COMMAND), | all XID parameters are evaluated and stored as global values, | if acceptable. Each XID parameter is tagged in llc_xid_tag | for the next response. Otherwise (a response has been | received), store the received parameters as global values | and reset their valid flags in llc_requested_xid. In each | case, if N201-I or N201-U have been changed, or if Layer-3 | XID parameters have been received, set xid_ind to TRUE, | otherwise to FALSE. Additionally remove any received parameter | in llc_xid_negotiate, because it has been explicitly | negotiated by the peer. | | Parameters : cr_bit - SGSN_COMMAND/_RESPONSE has been received | reset_received - TRUE indicates received Reset parameter, | else FALSE | xid_ind - TRUE indicates changed N201-U and/or N201-I, | so that LL_XID_IND must be sent to layer 3 | +------------------------------------------------------------------------------ */ GLOBAL void u_eval_xid (T_BIT cr_bit, BOOL *reset_received, BOOL *xid_ind) { UBYTE incarnation; TRACE_FUNCTION ("u_eval_xid"); /* * Preset both indicators with default values. */ *reset_received = FALSE; *xid_ind = FALSE; /* * Preset global XID indicator for next response. */ llc_data->u->xid_tag = 0L; /************************************************************************** * Reset: * Has to be processed first in order to take effect! */ if (llc_data->decoded_xid.reset.valid) { /* * Initialise all LLC layer parameters for all SAPIs. */ llc_init_parameters(); llc_init_requested_xid(); /* * Reset all incarnations of service U that are in state 'ABM' to 'ADM'. */ for (incarnation = 0; incarnation < U_NUM_INC; incarnation++) { llc_data->u_base[incarnation].state = U_ADM; } /* * LLC has to be reset. Send SIG_U_LLME_RESET_IND. */ *reset_received = TRUE; } /************************************************************************** * Version: * Shall not be negotiated while in state 'ABM'. * <R.LLC.XID_PAR.A.001> */ if ((llc_data->decoded_xid.version.valid) AND (GET_STATE(U) NEQ U_ABM)) { if (cr_bit EQ SGSN_COMMAND) { if (llc_xid_value_acceptable (llc_data->current_sapi, XID_VERSION, llc_data->decoded_xid.version.value)) { llc_data->version = llc_data->decoded_xid.version.value; } else /* value is not acceptable */ { /* * Sense of negotiation down: offer lower value; sense of * negotiation up: offer higher value. * This happens automatically by just responding with our current * global value. */ } /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_VERSION; } else /* SGSN_RESPONSE */ { /* * Sense of negotiation-correctness of response has already been checked * in u_check_xid(). */ llc_data->version = llc_data->decoded_xid.version.value; } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_VERSION); } /************************************************************************** * IOV-UI: * Shall only be negotiated in state 'ADM'. <R.LLC.XID_PAR.A.002> */ if ((llc_data->decoded_xid.iov_ui.valid) AND (GET_STATE(U) NEQ U_ABM) ) { /* * Do not tag iov_ui for the XID response, because it shall only be * transmitted in downlink direction. * <R.LLC.XID_PAR.A.004> */ /* * Copy value to global variable (no sense of negotiation). */ llc_data->iov_ui = llc_data->decoded_xid.iov_ui.value; } /************************************************************************** * IOV-I: * Shall only be negotiated with SABM and UA frames. This is already * checked in u_check_xid(). * <R.LLC.XID_PAR.A.003>, <R.LLC.XID_INVA.A.010> */ if (llc_data->decoded_xid.iov_i.valid) { /* * Do not tag iov_i for the XID response, because it shall only be * transmitted in downlink direction. * <R.LLC.XID_PAR.A.004> */ /* * Copy value to global variable (no sense of negotiation). */ *(llc_data->iov_i) = llc_data->decoded_xid.iov_i.value; } /************************************************************************** * T200 (and T201): * Can be negotiated in state 'ADM' and 'ABM'. New values shall only apply * to timers set after the negotiation has been completed (which is * accomplished automatically). * <R.LLC.XID_PAR.A.006>, <R.LLC.XID_PAR.A.007> */ if (llc_data->decoded_xid.t200.valid) { if (cr_bit EQ SGSN_COMMAND) { if (llc_xid_value_acceptable (llc_data->current_sapi, XID_T200, llc_data->decoded_xid.t200.value)) { llc_data->t200->length = XID2INT (llc_data->decoded_xid.t200.value); } else /* value is not acceptable */ { /* * Sense of negotiation down: offer lower value; sense of * negotiation up: offer higher value. * This happens automatically by just responding with our current * global value. */ } /* * In case we also want to negotiate this value, but to a lower! * value, delete this parameter from the requested XID structure */ if (llc_data->u->requested_xid.t200.valid AND llc_data->u->requested_xid.t200.value <= llc_data->decoded_xid.t200.value) { llc_data->u->requested_xid.t200.valid = FALSE; } /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_T200; } else /* SGSN_RESPONSE */ { /* * Sense of negotiation-correctness of response has already been checked * in u_check_xid(). */ llc_data->t200->length = XID2INT (llc_data->decoded_xid.t200.value); } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_T200); } /************************************************************************** * N200: * Can be negotiated in state 'ADM' and 'ABM'. * <R.LLC.XID_PAR.A.006> */ if (llc_data->decoded_xid.n200.valid) { if (cr_bit EQ SGSN_COMMAND) { if (llc_xid_value_acceptable (llc_data->current_sapi, XID_N200, llc_data->decoded_xid.n200.value)) { *(llc_data->n200) = llc_data->decoded_xid.n200.value; } else /* value is not acceptable */ { /* * Sense of negotiation down: offer lower value; sense of * negotiation up: offer higher value. * This happens automatically by just responding with our current * global value. */ } /* * In case we also want to negotiate this value, but to a lower! * value, delete this parameter from the requested XID structure */ if (llc_data->u->requested_xid.n200.valid AND llc_data->u->requested_xid.n200.value <= llc_data->decoded_xid.n200.value) { llc_data->u->requested_xid.n200.valid = FALSE; } /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_N200; } else /* SGSN_RESPONSE */ { /* * Sense of negotiation-correctness of response has already been checked * in u_check_xid(). */ *(llc_data->n200) = llc_data->decoded_xid.n200.value; } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_N200); } /************************************************************************** * N201-U: * Can be negotiated in state 'ADM' and 'ABM'. If N201-U is negotiated to a * lower value than previously used, then any queued or new U and UI frames * that violate the new value of N201-U should be discarded and not * transmitted. * <R.LLC.XID_PAR.A.006>, <R.LLC.XID_PAR.A.010> */ if (llc_data->decoded_xid.n201_u.valid) { if (cr_bit EQ SGSN_COMMAND) { if (llc_xid_value_acceptable (llc_data->current_sapi, XID_N201_U, llc_data->decoded_xid.n201_u.value)) { if (llc_data->decoded_xid.n201_u.value NEQ *(llc_data->n201_u)) { *(llc_data->n201_u) = llc_data->decoded_xid.n201_u.value; /* * LL_XID_IND has to be sent to layer 3. */ *xid_ind = TRUE; } } else /* value is not acceptable */ { /* * Sense of negotiation down: offer lower value; sense of * negotiation up: offer higher value. * This happens automatically by just responding with our current * global value. */ } /* * In case we also want to negotiate this value, but to a higher * value, delete this parameter from the requested XID structure */ if (llc_data->u->requested_xid.n201_u.valid AND llc_data->u->requested_xid.n201_u.value >= llc_data->decoded_xid.n201_u.value) { llc_data->u->requested_xid.n201_u.valid = FALSE; } /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_N201_U; } else /* SGSN_RESPONSE */ { if (llc_data->decoded_xid.n201_u.value NEQ *(llc_data->n201_u)) { /* * Sense of negotiation-correctness of response has already been checked * in u_check_xid(). */ *(llc_data->n201_u) = llc_data->decoded_xid.n201_u.value; /* * LL_XID_IND has to be sent to layer 3. */ *xid_ind = TRUE; } } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_N201_U); } /************************************************************************** * N201-I: * N201-I can be negotiated to any value in state 'ADM'. It can only be * negotiated to the same or higher value as previously used in state 'ABM'. * <R.LLC.XID_PAR.A.008>, <R.LLC.XID_PAR.A.009> */ if (llc_data->decoded_xid.n201_i.valid) { if (cr_bit EQ SGSN_COMMAND) { if (llc_xid_value_acceptable (llc_data->current_sapi, XID_N201_I, llc_data->decoded_xid.n201_i.value)) { if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.n201_i.value > *(llc_data->n201_i))) OR /* state 'ADM' */ (llc_data->decoded_xid.n201_i.value NEQ *(llc_data->n201_i))) { *(llc_data->n201_i) = llc_data->decoded_xid.n201_i.value; /* * LL_XID_IND has to be sent to layer 3. */ *xid_ind = TRUE; } } else /* value is not acceptable */ { /* * Sense of negotiation down: offer lower value; sense of * negotiation up: offer higher value. * This happens automatically by just responding with our current * global value. */ } /* * In case we also want to negotiate this value, but to a higher * value, delete this parameter from the requested XID structure */ if (llc_data->u->requested_xid.n201_i.valid AND llc_data->u->requested_xid.n201_i.value >= llc_data->decoded_xid.n201_i.value) { llc_data->u->requested_xid.n201_i.valid = FALSE; } /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_N201_I; } else /* SGSN_RESPONSE */ { /* * Sense of negotiation-correctness of response has already been checked * in u_check_xid(). */ if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.n201_i.value > *(llc_data->n201_i))) OR /* state 'ADM' */ (llc_data->decoded_xid.n201_i.value NEQ *(llc_data->n201_i))) { *(llc_data->n201_i) = llc_data->decoded_xid.n201_i.value; /* * LL_XID_IND has to be sent to layer 3. */ *xid_ind = TRUE; } } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_N201_I); } /************************************************************************** * mD: * mD can be negotiated to any value in state 'ADM'. It can only be * negotiated to the same or higher value as previously used in state 'ABM'. * <R.LLC.XID_PAR.A.008>, <R.LLC.XID_PAR.A.009> */ if (llc_data->decoded_xid.md.valid) { if (cr_bit EQ SGSN_COMMAND) { if (llc_xid_value_acceptable (llc_data->current_sapi, XID_MD, llc_data->decoded_xid.md.value)) { if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.md.value > *(llc_data->md))) OR /* state 'ADM' */ (llc_data->decoded_xid.md.value NEQ *(llc_data->md))) { *(llc_data->md) = llc_data->decoded_xid.md.value; } } else /* value is not acceptable */ { /* * Sense of negotiation down: offer lower value; sense of * negotiation up: offer higher value. * This happens automatically by just responding with our current * global value. */ } /* * In case we also want to negotiate this value, but to a higher * value, delete this parameter from the requested XID structure */ if (llc_data->u->requested_xid.md.valid AND llc_data->u->requested_xid.md.value >= llc_data->decoded_xid.md.value) { llc_data->u->requested_xid.md.valid = FALSE; } /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_MD; } else /* SGSN_RESPONSE */ { /* * Sense of negotiation-correctness of response has already been checked * in u_check_xid(). */ if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.md.value > *(llc_data->md))) OR /* state 'ADM' */ (llc_data->decoded_xid.md.value NEQ *(llc_data->md))) { *(llc_data->md) = llc_data->decoded_xid.md.value; } } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_MD); } /************************************************************************** * mU: * mU can be negotiated to any value in state 'ADM'. It can only be * negotiated to the same or higher value as previously used in state 'ABM'. * <R.LLC.XID_PAR.A.008>, <R.LLC.XID_PAR.A.009> */ if (llc_data->decoded_xid.mu.valid) { if (cr_bit EQ SGSN_COMMAND) { if (llc_xid_value_acceptable (llc_data->current_sapi, XID_MU, llc_data->decoded_xid.mu.value)) { if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.mu.value > *(llc_data->mu))) OR /* state 'ADM' */ (llc_data->decoded_xid.mu.value NEQ *(llc_data->mu))) { *(llc_data->mu) = llc_data->decoded_xid.mu.value; } } else /* value is not acceptable */ { /* * Sense of negotiation down: offer lower value; sense of * negotiation up: offer higher value. * This happens automatically by just responding with our current * global value. */ } /* * In case we also want to negotiate this value, but to a higher * value, delete this parameter from the requested XID structure */ if (llc_data->u->requested_xid.mu.valid AND llc_data->u->requested_xid.mu.value >= llc_data->decoded_xid.mu.value) { llc_data->u->requested_xid.mu.valid = FALSE; } /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_MU; } else /* SGSN_RESPONSE */ { /* * Sense of negotiation-correctness of response has already been checked * in u_check_xid(). */ if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.mu.value > *(llc_data->mu))) OR /* state 'ADM' */ (llc_data->decoded_xid.mu.value NEQ *(llc_data->mu))) { *(llc_data->mu) = llc_data->decoded_xid.mu.value; } } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_MU); } /************************************************************************** * kD: * kD can be negotiated to any value in state 'ADM'. It can only be * negotiated to the same or higher value as previously used in state 'ABM'. * <R.LLC.XID_PAR.A.008>, <R.LLC.XID_PAR.A.009> */ if (llc_data->decoded_xid.kd.valid) { if (cr_bit EQ SGSN_COMMAND) { if (llc_xid_value_acceptable (llc_data->current_sapi, XID_KD, llc_data->decoded_xid.kd.value)) { if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.kd.value > *(llc_data->kd))) OR /* state 'ADM' */ (llc_data->decoded_xid.kd.value NEQ *(llc_data->kd))) { *(llc_data->kd) = llc_data->decoded_xid.kd.value; } } else /* value is not acceptable */ { /* * Sense of negotiation down: offer lower value; sense of * negotiation up: offer higher value. * This happens automatically by just responding with our current * global value. */ } /* * In case we also want to negotiate this value, but to a higher * value, delete this parameter from the requested XID structure */ if (llc_data->u->requested_xid.kd.valid AND llc_data->u->requested_xid.kd.value >= llc_data->decoded_xid.kd.value) { llc_data->u->requested_xid.kd.valid = FALSE; } /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_KD; } else /* SGSN_RESPONSE */ { /* * Sense of negotiation-correctness of response has already been checked * in u_check_xid(). */ if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.kd.value > *(llc_data->kd))) OR /* state 'ADM' */ (llc_data->decoded_xid.kd.value NEQ *(llc_data->kd))) { *(llc_data->kd) = llc_data->decoded_xid.kd.value; } } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_KD); } /************************************************************************** * kU: * kU can be negotiated to any value in state 'ADM'. It can only be * negotiated to the same or higher value as previously used in state 'ABM'. * <R.LLC.XID_PAR.A.008>, <R.LLC.XID_PAR.A.009> */ if (llc_data->decoded_xid.ku.valid) { if (cr_bit EQ SGSN_COMMAND) { if (llc_xid_value_acceptable (llc_data->current_sapi, XID_KU, llc_data->decoded_xid.ku.value)) { if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.ku.value > *(llc_data->ku))) OR /* state 'ADM' */ (llc_data->decoded_xid.ku.value NEQ *(llc_data->ku))) { *(llc_data->ku) = llc_data->decoded_xid.ku.value; } } else /* value is not acceptable */ { /* * Sense of negotiation down: offer lower value; sense of * negotiation up: offer higher value. * This happens automatically by just responding with our current * global value. */ } /* * In case we also want to negotiate this value, but to a higher * value, delete this parameter from the requested XID structure */ if (llc_data->u->requested_xid.ku.valid AND llc_data->u->requested_xid.ku.value >= llc_data->decoded_xid.ku.value) { llc_data->u->requested_xid.ku.valid = FALSE; } /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_KU; } else /* SGSN_RESPONSE */ { /* * Sense of negotiation-correctness of response has already been checked * in u_check_xid(). */ if (((GET_STATE (U) EQ U_ABM) AND (llc_data->decoded_xid.ku.value > *(llc_data->ku))) OR /* state 'ADM' */ (llc_data->decoded_xid.ku.value NEQ *(llc_data->ku))) { *(llc_data->ku) = llc_data->decoded_xid.ku.value; } } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_KU); } /************************************************************************** * Layer 3 stuff */ if (llc_data->decoded_l3_xid.valid) { /* * LL_XID_IND has to be sent to layer 3. */ *xid_ind = TRUE; if (cr_bit EQ SGSN_COMMAND) { /* * Tag parameter for next response. */ llc_data->u->xid_tag |= 0x00000001L << XID_LAYER_3; } else /* SGSN_RESPONSE */ { /* * Reset valid flag of parameter in requested_xid because it has been * included in the response. */ llc_data->requested_l3_xid->valid = FALSE; } /* * Remove tag in xid_tag_negotiate, because this parameter has been * explicitly negotiated by the peer. * <R.LLC.XIDNEG_R.A.015> */ llc_data->u->xid_tag_negotiate &= ~(0x00000001L << XID_LAYER_3); } return; /* u_eval_xid */ } /* +------------------------------------------------------------------------------ | Function : u_insert_xid +------------------------------------------------------------------------------ | Description : This procedure inserts (i.e. appends) the XID parameters that | are tagged in llc_xid_tag. This variable is normally set in | u_eval_xid(). The parameter cr_bit indicates if the XID | information field is written in a command or a response frame. | The values of the parameters are taken from llc_requested_xid | if marked as valid (normally the cause when a command frame is | to be sent), otherwise from global variables (the normal cause | for a response frame). If a response frame is to be sent, and | the parameter is tagged in llc_xid_tag, but has not been | received in the command frame (as indicated by | llc_decoded_xid), the parameter is tagged in llc_xid_negotiate. | Each parameter is tagged in llc_xid_tag_sent for collision | checks and the like | | Parameters : sdu - a valid pointer to an SDU, containing enough octets | for the tagged number of XID parameters | cr_bit - MS_COMMAND/_RESPONSE is to be sent | +------------------------------------------------------------------------------ */ GLOBAL void u_insert_xid ( #ifdef LL_DESC T_desc_list3 *desc_list3, #else T_sdu *sdu, #endif T_BIT cr_bit ) { UBYTE *data; ULONG value; #ifdef LL_DESC UBYTE *desc_buf; T_desc3 *desc3; #endif TRACE_FUNCTION( "u_insert_xid" ); /* * Set data to point to the first free data octet in sdu. data has to * be incremented with each octet that is written in sdu to ensure that * it always points to the first free data octet. */ #ifdef LL_DESC desc3 = (T_desc3*) desc_list3->first; desc_buf = (UBYTE*)desc3->buffer; data = &desc_buf[(desc3->offset)+(desc3->len)]; #else data = &sdu->buf[(sdu->o_buf/8)+(sdu->l_buf/8)]; #endif /* * Preset global XID sent indicator for next response. */ llc_data->u->xid_tag_sent = 0L; /************************************************************************* * Version: * Shall not be negotiated while in state 'ABM'. * <R.LLC.XID_PAR.A.001> */ if (llc_data->u->xid_tag & (0x00000001L << XID_VERSION) AND (GET_STATE (U) NEQ U_ABM)) { if (cr_bit EQ MS_COMMAND) { value = llc_data->u->requested_xid.version.value; } else { if (llc_data->u->requested_xid.version.valid) { llc_data->version = llc_data->u->requested_xid.version.value; } value = llc_data->version; /* * Tag a parameter for further negotiation that was not included in * the XID command in every XID response until the parameter has been * explicitly negotiated, either by responding to an XID command that * included the parameter, or by explicitly including the parameter * the next time an XID command is transmitted. * <R.LLC.XIDNEG_R.A.015> */ if (!llc_data->decoded_xid.version.valid) { llc_data->u->xid_tag_negotiate |= 0x00000001L << XID_VERSION; } } /* * Append determined value to SDU data, increment SDU data pointer to * point to the first free data octet again. */ *data++ = (UBYTE)0x00 | ((UBYTE)XID_VERSION << 2) | (UBYTE)XID_VERSION_LEN; *data++ = (UBYTE)value; #ifdef LL_DESC desc3->len += (XID_VERSION_LEN + 1); #else sdu->l_buf += (XID_VERSION_LEN + 1) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_VERSION; } /************************************************************************* * T200: * Can be negotiated in state 'ADM' and 'ABM'. * <R.LLC.XID_PAR.A.006> */ if (llc_data->u->xid_tag & (0x00000001L << XID_T200)) { if (cr_bit EQ MS_COMMAND) { value = llc_data->u->requested_xid.t200.value; } else { if (llc_data->u->requested_xid.t200.valid) { llc_data->t200->length = XID2INT(llc_data->u->requested_xid.t200.value); } value = INT2XID(llc_data->t200->length); /* * Tag a parameter for further negotiation that was not included in * the XID command in every XID response until the parameter has been * explicitly negotiated, either by responding to an XID command that * included the parameter, or by explicitly including the parameter * the next time an XID command is transmitted. * <R.LLC.XIDNEG_R.A.015> */ if (!llc_data->decoded_xid.t200.valid) { llc_data->u->xid_tag_negotiate |= 0x00000001L << XID_T200; } } /* * Append determined value to SDU data, increment SDU data pointer to * point to the first free data octet again. */ *data++ = (UBYTE)0x00 | ((UBYTE)XID_T200 << 2) | (UBYTE)XID_T200_LEN; *data++ = (UBYTE)(value >> 8); *data++ = (UBYTE)value; #ifdef LL_DESC desc3->len += (XID_T200_LEN + 1); #else sdu->l_buf += (XID_T200_LEN + 1) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_T200; } /************************************************************************* * N200: * Can be negotiated in state 'ADM' and 'ABM'. * <R.LLC.XID_PAR.A.006> */ if (llc_data->u->xid_tag & (0x00000001L << XID_N200)) { if (cr_bit EQ MS_COMMAND) { value = llc_data->u->requested_xid.n200.value; } else { if (llc_data->u->requested_xid.n200.valid) { *(llc_data->n200) = llc_data->u->requested_xid.n200.value; } value = *(llc_data->n200); /* * Tag a parameter for further negotiation that was not included in * the XID command in every XID response until the parameter has been * explicitly negotiated, either by responding to an XID command that * included the parameter, or by explicitly including the parameter * the next time an XID command is transmitted. * <R.LLC.XIDNEG_R.A.015> */ if (!llc_data->decoded_xid.n200.valid) { llc_data->u->xid_tag_negotiate |= 0x00000001L << XID_N200; } } /* * Append determined value to SDU data, increment SDU data pointer to * point to the first free data octet again. */ *data++ = (UBYTE)0x00 | ((UBYTE)XID_N200 << 2) | (UBYTE)XID_N200_LEN; *data++ = (UBYTE)value; #ifdef LL_DESC desc3->len += (XID_N200_LEN + 1); #else sdu->l_buf += (XID_N200_LEN + 1) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_N200; } /************************************************************************* * N201-U: * Can be negotiated in state 'ADM' and 'ABM'. * <R.LLC.XID_PAR.A.006> */ if (llc_data->u->xid_tag & (0x00000001L << XID_N201_U)) { if (cr_bit EQ MS_COMMAND) { value = llc_data->u->requested_xid.n201_u.value; } else { if (llc_data->u->requested_xid.n201_u.valid) { *(llc_data->n201_u) = llc_data->u->requested_xid.n201_u.value; } value = *(llc_data->n201_u); /* * Tag a parameter for further negotiation that was not included in * the XID command in every XID response until the parameter has been * explicitly negotiated, either by responding to an XID command that * included the parameter, or by explicitly including the parameter * the next time an XID command is transmitted. * <R.LLC.XIDNEG_R.A.015> */ if (!llc_data->decoded_xid.n201_u.valid) { llc_data->u->xid_tag_negotiate |= 0x00000001L << XID_N201_U; } } /* * Append determined value to SDU data, increment SDU data pointer to * point to the first free data octet again. */ *data++ = (UBYTE)0x00 | ((UBYTE)XID_N201_U << 2) | (UBYTE)XID_N201_U_LEN; *data++ = (UBYTE)(value >> 8); *data++ = (UBYTE)value; #ifdef LL_DESC desc3->len += (XID_N201_U_LEN + 1); #else sdu->l_buf += (XID_N201_U_LEN + 1) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_N201_U; } /************************************************************************* * N201-I: * Can be negotiated in state 'ADM' and 'ABM'. * <R.LLC.XID_PAR.A.006> */ if (llc_data->u->xid_tag & (0x00000001L << XID_N201_I)) { if (cr_bit EQ MS_COMMAND) { value = llc_data->u->requested_xid.n201_i.value; } else { if (llc_data->u->requested_xid.n201_i.valid) { *(llc_data->n201_i) = llc_data->u->requested_xid.n201_i.value; } value = *(llc_data->n201_i); /* * Tag a parameter for further negotiation that was not included in * the XID command in every XID response until the parameter has been * explicitly negotiated, either by responding to an XID command that * included the parameter, or by explicitly including the parameter * the next time an XID command is transmitted. * <R.LLC.XIDNEG_R.A.015> */ if (!llc_data->decoded_xid.n201_i.valid) { llc_data->u->xid_tag_negotiate |= 0x00000001L << XID_N201_I; } } /* * Append determined value to SDU data, increment SDU data pointer to * point to the first free data octet again. */ *data++ = (UBYTE)0x00 | ((UBYTE)XID_N201_I << 2) | (UBYTE)XID_N201_I_LEN; *data++ = (UBYTE)(value >> 8); *data++ = (UBYTE)value; #ifdef LL_DESC desc3->len += (XID_N201_I_LEN + 1); #else sdu->l_buf += (XID_N201_I_LEN + 1) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_N201_I; } /************************************************************************* * md: * Can be negotiated in state 'ADM' and 'ABM'. * <R.LLC.XID_PAR.A.006> */ if (llc_data->u->xid_tag & (0x00000001L << XID_MD)) { if (cr_bit EQ MS_COMMAND) { value = llc_data->u->requested_xid.md.value; } else { if (llc_data->u->requested_xid.md.valid) { *(llc_data->md) = llc_data->u->requested_xid.md.value; } value = *(llc_data->md); /* * Tag a parameter for further negotiation that was not included in * the XID command in every XID response until the parameter has been * explicitly negotiated, either by responding to an XID command that * included the parameter, or by explicitly including the parameter * the next time an XID command is transmitted. * <R.LLC.XIDNEG_R.A.015> */ if (!llc_data->decoded_xid.md.valid) { llc_data->u->xid_tag_negotiate |= 0x00000001L << XID_MD; } } /* * Append determined value to SDU data, increment SDU data pointer to * point to the first free data octet again. */ *data++ = (UBYTE)0x00 | ((UBYTE)XID_MD << 2) | (UBYTE)XID_MD_LEN; *data++ = (UBYTE)(value >> 8); *data++ = (UBYTE)value; #ifdef LL_DESC desc3->len += (XID_MD_LEN + 1); #else sdu->l_buf += (XID_MD_LEN + 1) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_MD; } /************************************************************************* * mu: * Can be negotiated in state 'ADM' and 'ABM'. * <R.LLC.XID_PAR.A.006> */ if (llc_data->u->xid_tag & (0x00000001L << XID_MU)) { if (cr_bit EQ MS_COMMAND) { value = llc_data->u->requested_xid.mu.value; } else { if (llc_data->u->requested_xid.mu.valid) { *(llc_data->mu) = llc_data->u->requested_xid.mu.value; } value = *(llc_data->mu); /* * Tag a parameter for further negotiation that was not included in * the XID command in every XID response until the parameter has been * explicitly negotiated, either by responding to an XID command that * included the parameter, or by explicitly including the parameter * the next time an XID command is transmitted. * <R.LLC.XIDNEG_R.A.015> */ if (!llc_data->decoded_xid.mu.valid) { llc_data->u->xid_tag_negotiate |= 0x00000001L << XID_MU; } } /* * Append determined value to SDU data, increment SDU data pointer to * point to the first free data octet again. */ *data++ = (UBYTE)0x00 | ((UBYTE)XID_MU << 2) | (UBYTE)XID_MU_LEN; *data++ = (UBYTE)(value >> 8); *data++ = (UBYTE)value; #ifdef LL_DESC desc3->len += (XID_MU_LEN + 1); #else sdu->l_buf += (XID_MU_LEN + 1) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_MU; } /************************************************************************* * kd: * Can be negotiated in state 'ADM' and 'ABM'. * <R.LLC.XID_PAR.A.006> */ if (llc_data->u->xid_tag & (0x00000001L << XID_KD)) { if (cr_bit EQ MS_COMMAND) { value = llc_data->u->requested_xid.kd.value; } else { if (llc_data->u->requested_xid.kd.valid) { *(llc_data->kd) = llc_data->u->requested_xid.kd.value; } value = *(llc_data->kd); /* * Tag a parameter for further negotiation that was not included in * the XID command in every XID response until the parameter has been * explicitly negotiated, either by responding to an XID command that * included the parameter, or by explicitly including the parameter * the next time an XID command is transmitted. * <R.LLC.XIDNEG_R.A.015> */ if (!llc_data->decoded_xid.kd.valid) { llc_data->u->xid_tag_negotiate |= 0x00000001L << XID_KD; } } /* * Append determined value to SDU data, increment SDU data pointer to * point to the first free data octet again. */ *data++ = (UBYTE)0x00 | ((UBYTE)XID_KD << 2) | (UBYTE)XID_KD_LEN; *data++ = (UBYTE)value; #ifdef LL_DESC desc3->len += (XID_KD_LEN + 1); #else sdu->l_buf += (XID_KD_LEN + 1) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_KD; } /************************************************************************* * ku: * Can be negotiated in state 'ADM' and 'ABM'. * <R.LLC.XID_PAR.A.006> */ if (llc_data->u->xid_tag & (0x00000001L << XID_KU)) { if (cr_bit EQ MS_COMMAND) { value = llc_data->u->requested_xid.ku.value; } else { if (llc_data->u->requested_xid.ku.valid) { *(llc_data->ku) = llc_data->u->requested_xid.ku.value; } value = *(llc_data->ku); /* * Tag a parameter for further negotiation that was not included in * the XID command in every XID response until the parameter has been * explicitly negotiated, either by responding to an XID command that * included the parameter, or by explicitly including the parameter * the next time an XID command is transmitted. * <R.LLC.XIDNEG_R.A.015> */ if (!llc_data->decoded_xid.ku.valid) { llc_data->u->xid_tag_negotiate |= 0x00000001L << XID_KU; } } /* * Append determined value to SDU data, increment SDU data pointer to * point to the first free data octet again. */ *data++ = (UBYTE)0x00 | ((UBYTE)XID_KU << 2) | (UBYTE)XID_KU_LEN; *data++ = (UBYTE)value; #ifdef LL_DESC desc3->len += (XID_KU_LEN + 1); #else sdu->l_buf += (XID_KU_LEN + 1) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_KU; } /************************************************************************* * Insert Layer 3 (sense of negotiation: both) */ if (llc_data->u->xid_tag & (0x00000001L << XID_LAYER_3)) { if (llc_data->requested_l3_xid->valid) { /* * Write two bytes header */ *data++ = (UBYTE)0x80 /* = set length to 8 bit */ | ((UBYTE)XID_LAYER_3 << 2) | ((UBYTE)((llc_data->requested_l3_xid->length >> 6) & 0x03)); *data++ = (UBYTE)(llc_data->requested_l3_xid->length << 2); /* * Copy data */ memcpy (data, llc_data->requested_l3_xid->value, llc_data->requested_l3_xid->length); /* * Increase DESC/SDU size */ #ifdef LL_DESC desc3->len += (llc_data->requested_l3_xid->length + 2); #else sdu->l_buf += (llc_data->requested_l3_xid->length + 2) * 8; #endif /* * Tag parameter for collision checks and the like. */ llc_data->u->xid_tag_sent |= 0x00000001L << XID_LAYER_3; } } #ifdef LL_DESC desc_list3->list_len = desc3->len; #endif /* LL_DESC */ #ifdef TRACE_EVE #ifdef LL_DESC { int i; int l = desc3->len; int o = desc3->offset; vsi_o_ttrace(VSI_CALLER TC_EVENT, "ul XID sdu dump len:%d bytes", l); for (i=0; i<l; i+=10) { vsi_o_ttrace(VSI_CALLER TC_EVENT, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x", desc_buf[o+i+0], desc_buf[o+i+1], desc_buf[o+i+2], desc_buf[o+i+3], desc_buf[o+i+4], desc_buf[o+i+5], desc_buf[o+i+6], desc_buf[o+i+7], desc_buf[o+i+8], desc_buf[o+i+9]); } } #else { int i; int l = sdu->l_buf/8; int o = sdu->o_buf/8; vsi_o_ttrace(VSI_CALLER TC_EVENT, "ul XID sdu dump len:%d bytes", l); for (i=0; i<l; i+=10) { vsi_o_ttrace(VSI_CALLER TC_EVENT, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x", sdu->buf[o+i+0], sdu->buf[o+i+1], sdu->buf[o+i+2], sdu->buf[o+i+3], sdu->buf[o+i+4], sdu->buf[o+i+5], sdu->buf[o+i+6], sdu->buf[o+i+7], sdu->buf[o+i+8], sdu->buf[o+i+9]); } } #endif /* LL_DESC */ #endif /* TRACE_EVE */ /* * If we have build an response including all XID parameters, * we can clean all the xid_tags and layer 3 parameters. */ if (cr_bit EQ MS_RESPONSE) { llc_data->u->xid_tag = 0; llc_data->requested_l3_xid->valid = FALSE; } return; } /* u_insert_xid() */ /* +------------------------------------------------------------------------------ | Function : u_insert_frmr_information +------------------------------------------------------------------------------ | Description : This procedure inserts (i.e. appends) an FRMR information | field into the given sdu. frame is the rejected frame of which | the control field is included (ctrl_length is truncated to a | maximum of six octets; if it is not known, length is | determinated from pdu_type), v_s and v_r are the current | send and receive state numbers of ITX/IRX, cr_bit indicates | if the frame was a command or response (SGSN_COMMAND/RESPONSE), | and reason indicates the reason of the frame rejection | condition (the lower nibble of reason is equivalent to W4-W1). | | Parameters : sdu - a valid pointer to an SDU, containing enough | octets for the FRMR information field | (U_FRMR_INFO_SIZE) | frame - frame that caused the frame rejection condition | pdu_type - frame type | ctrl_length - control field length, if known | v_s - current V(S) | v_r - current V(R) | cr_bit - setting of C/R bit in frame | reason - reason of the frame rejection condition (lower | nibble conforms to W4-W1 in FRMR response) | +------------------------------------------------------------------------------ */ GLOBAL void u_insert_frmr_information ( #ifndef LL_DESC T_sdu *sdu, #else T_desc_list3 *desc_list3, #endif T_LL_UNITDATA_IND *frame, T_PDU_TYPE pdu_type, USHORT ctrl_length, T_FRAME_NUM v_s, T_FRAME_NUM v_r, T_BIT cr_bit, UBYTE reason ) { #ifndef LL_DESC UBYTE *sdu_data; #else UBYTE *help, *desc_data; T_desc3 *desc3; #endif UBYTE *ctrl; USHORT octet; TRACE_FUNCTION( "u_insert_frmr_information" ); #ifndef LL_DESC /* * Set sdu_data to point to the first free data octet in sdu. sdu_data * has to be incremented with each octet that is written in sdu to ensure * that it always points to the first free data octet. */ sdu_data = &sdu->buf[(sdu->o_buf/8)+(sdu->l_buf/8)]; /* * Adjust length of SDU to include fixed sized FRMR information field. */ sdu->l_buf += U_FRMR_INFO_SIZE * 8; /* * Set ctrl to point to the first octet of the faulty frame control field. */ ctrl = &frame->sdu.buf[(frame->sdu.o_buf/8)+1]; /* * If ctrl_length is unknown, the frame type is known, therefore the length * of the control field can be easily determined. */ if (ctrl_length EQ FRMR_CTRL_LENGTH_UNKNOWN) { if (pdu_type EQ I_FRAME) { ctrl_length = I_CTRL_OCTETS; } else if (pdu_type EQ S_FRAME) { ctrl_length = S_CTRL_OCTETS; } else if (pdu_type EQ UI_FRAME) { ctrl_length = UI_CTRL_OCTETS; } else if (pdu_type EQ U_FRAME) { ctrl_length = U_CTRL_OCTETS; } else { /* * Undefined control field type, set control field length to SDU length * minus address field, limited to six octets. */ TRACE_ERROR ("undefined control field type"); ctrl_length = (sdu->l_buf/8 - 1) < 6 ? (sdu->l_buf/8 - 1) : 6; } } else /* ctrl_length is already known */ { /* * Limit control field length to six octets, according to 04.64. */ ctrl_length = ctrl_length < 6 ? ctrl_length : 6; } /* * Copy the first six octets of faulty control field. If the control field * is smaller that six octets, the unused octets are set to 0. */ for (octet = 0; octet < 6; octet++) { if (octet < ctrl_length) { sdu_data[octet] = ctrl[octet]; } else { sdu_data[octet] = 0x00; } } /* * Insert remaining four octets of FRMR information field: * +---+---+---+---+---+---+---+---+ * | X | X | X | X | V(S) | * +---+---+---+---+---+---+---+---+ * | V(S) | X | V(R) | * +---+---+---+---+---+---+---+---+ * | V(R) |C/R| * +---+---+---+---+---+---+---+---+ * | X | X | X | X | W4| W3| W2| W1| * +---+---+---+---+---+---+---+---+ */ sdu_data[octet++] = (UBYTE)(v_s >> 5) & 0x0F; sdu_data[octet++] = (UBYTE)(v_s << 3) | ((UBYTE)(v_r >> 7) & 0x0003); sdu_data[octet++] = (UBYTE)(v_r << 1) | (cr_bit EQ SGSN_COMMAND ? 0x00 : 0x01); sdu_data[octet++] = reason & 0x0F; return; #else /* * Set sdu_data to point to the first free data octet in sdu. sdu_data * has to be incremented with each octet that is written in sdu to ensure * that it always points to the first free data octet. */ desc3 = (T_desc3*)desc_list3->first; help = (U8*)desc3->buffer; desc_data = &help[desc3->offset + desc3->len]; /* * Adjust length of SDU to include fixed sized FRMR information field. */ desc3->len += U_FRMR_INFO_SIZE; desc_list3->list_len += U_FRMR_INFO_SIZE; /* * Set ctrl to point to the first octet of the faulty frame control field. */ ctrl = &frame->sdu.buf[(frame->sdu.o_buf/8)+1]; /* * If ctrl_length is unknown, the frame type is known, therefore the length * of the control field can be easily determined. */ if (ctrl_length EQ FRMR_CTRL_LENGTH_UNKNOWN) { if (pdu_type EQ I_FRAME) { ctrl_length = I_CTRL_OCTETS; } else if (pdu_type EQ S_FRAME) { ctrl_length = S_CTRL_OCTETS; } else if (pdu_type EQ UI_FRAME) { ctrl_length = UI_CTRL_OCTETS; } else if (pdu_type EQ U_FRAME) { ctrl_length = U_CTRL_OCTETS; } else { /* * Undefined control field type, set control field length to SDU length * minus address field, limited to six octets. */ TRACE_ERROR ("undefined control field type"); ctrl_length = desc3->len - 1 < 6 ? (desc3->len - 1) : 6; } } else /* ctrl_length is already known */ { /* * Limit control field length to six octets, according to 04.64. */ ctrl_length = ctrl_length < 6 ? ctrl_length : 6; } /* * Copy the first six octets of faulty control field. If the control field * is smaller that six octets, the unused octets are set to 0. */ for (octet = 0; octet < 6; octet++) { if (octet < ctrl_length) { desc_data[octet] = ctrl[octet]; } else { desc_data[octet] = 0x00; } } /* * Insert remaining four octets of FRMR information field: * +---+---+---+---+---+---+---+---+ * | X | X | X | X | V(S) | * +---+---+---+---+---+---+---+---+ * | V(S) | X | V(R) | * +---+---+---+---+---+---+---+---+ * | V(R) |C/R| * +---+---+---+---+---+---+---+---+ * | X | X | X | X | W4| W3| W2| W1| * +---+---+---+---+---+---+---+---+ */ desc_data[octet++] = (UBYTE)(v_s >> 5) & 0x0F; desc_data[octet++] = (UBYTE)(v_s << 3) | ((UBYTE)(v_r >> 7) & 0x0003); desc_data[octet++] = (UBYTE)(v_r << 1) | (cr_bit EQ SGSN_COMMAND ? 0x00 : 0x01); desc_data[octet++] = reason & 0x0F; return; #endif } /* u_insert_frmr_information() */ /* +------------------------------------------------------------------------------ | Function : u_send_sabm +------------------------------------------------------------------------------ | Description : This procedure allocates a LL_UNITDATA_REQ primitive, fills in | the required parameters, builds an U frame header containing | an SABM command, and sends this primitive to TX. _Before_ it is | sent to TX, T200 has to be started, because otherwise the | primitive may not be valid anymore. | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_send_sabm (void) { USHORT sdu_byte_len = 0; #ifdef LL_DESC T_desc3 *desc3; #endif TRACE_FUNCTION( "u_send_sabm" ); u_tag_xid_parameters(0, TRUE); /* * Calculate bit length of tagged XID parameters. First, add * the size of each tagged parameter. The size of layer-3 * parameters is variable, so add the given length in octets. */ ADD_IF_TAGGED (sdu_byte_len, XID_VERSION); ADD_IF_TAGGED (sdu_byte_len, XID_T200); ADD_IF_TAGGED (sdu_byte_len, XID_N200); ADD_IF_TAGGED (sdu_byte_len, XID_N201_U); ADD_IF_TAGGED (sdu_byte_len, XID_N201_I); ADD_IF_TAGGED (sdu_byte_len, XID_MD); ADD_IF_TAGGED (sdu_byte_len, XID_MU); ADD_IF_TAGGED (sdu_byte_len, XID_KD); ADD_IF_TAGGED (sdu_byte_len, XID_KU); if (llc_data->u->xid_tag & (0x00000001L << XID_LAYER_3)) { sdu_byte_len += llc_data->requested_l3_xid->length + 2; } /* * Add SDU header and FCS field to the XID response size to get * the overall SDU size. */ sdu_byte_len += U_HDR_SIZE + FCS_SIZE; #ifdef LL_DESC { PALLOC(ll_unitdesc_req, LL_UNITDESC_REQ); desc3 = llc_palloc_desc((USHORT)sdu_byte_len, 0); /* One desc3 descriptor and buffer allocated */ ll_unitdesc_req->sapi = llc_data->current_sapi; ll_unitdesc_req->tlli = llc_data->u->current_tlli; /* * No attach to primitive necessary. For retransmission prim * data is copied in T200. */ ll_unitdesc_req->attached_counter = CCI_NO_ATTACHE; /* * LLC does not know the QoS profile. */ 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 */ /* * Set parameter of descriptor list3 */ ll_unitdesc_req->desc_list3.first = (ULONG)desc3; ll_unitdesc_req->desc_list3.list_len = desc3->len; u_build_u_frame (&ll_unitdesc_req->desc_list3, MS_COMMAND, llc_data->current_sapi, 1, U_SABM); u_insert_xid (&ll_unitdesc_req->desc_list3, MS_COMMAND); /* * T200 has to be started _before_ the primitive is sent to TX, because * the primitive is copied by t200_start() and it may not be valid * anymore after sending to TX. */ sig_u_t200_start_req (ll_unitdesc_req, GRLC_DTACS_DEF); sig_u_tx_data_req (ll_unitdesc_req, GRLC_DTACS_DEF); } #else { PALLOC_SDU (ll_unitdata_req, LL_UNITDATA_REQ, (USHORT)(sdu_byte_len*8)); ll_unitdata_req->sapi = llc_data->current_sapi; ll_unitdata_req->tlli = llc_data->u->current_tlli; /* * No attach to primitive necessary. For retransmission prim * data is copied in T200. */ ll_unitdata_req->attached_counter = CCI_NO_ATTACHE; /* * LLC does not know the QoS profile. */ ll_unitdata_req->ll_qos.peak = LL_PEAK_SUB; /* * LLC signalling frames are always sent with highest priority. */ ll_unitdata_req->radio_prio = LL_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_unitdata_req->pkt_flow_id = LL_PFI_SIGNALING; #endif /* REL99 */ u_build_u_frame (&ll_unitdata_req->sdu, MS_COMMAND, llc_data->current_sapi, 1, U_SABM); u_insert_xid (&ll_unitdata_req->sdu, MS_COMMAND); /* * T200 has to be started _before_ the primitive is sent to TX, because * the primitive is copied by t200_start() and it may not be valid * anymore after sending to TX. */ sig_u_t200_start_req (ll_unitdata_req, GRLC_DTACS_DEF); sig_u_tx_data_req (ll_unitdata_req, GRLC_DTACS_DEF); } #endif return; } /* u_send_sabm() */ /* +------------------------------------------------------------------------------ | Function : u_send_disc +------------------------------------------------------------------------------ | Description : This procedure allocates a LL_UNITDATA_REQ primitive, fills in | the required parameters, builds an U frame header containing | an DISC command, and sends this primitive to TX. _Before_ it is | sent to TX, T200 has to be started, because otherwise the | primitive may not be valid anymore. | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_send_disc (void) { #ifdef LL_DESC T_desc3* desc3; #endif TRACE_FUNCTION( "u_send_disc" ); { #ifndef LL_DESC PALLOC_SDU (ll_unitdesc_req, LL_UNITDATA_REQ, U_HDR_SIZE_BITS + FCS_SIZE_BITS); #else PALLOC (ll_unitdesc_req, LL_UNITDESC_REQ); desc3 = llc_palloc_desc((U_HDR_SIZE_BITS + FCS_SIZE_BITS)/8, 0); ll_unitdesc_req->desc_list3.first = (ULONG)desc3; ll_unitdesc_req->desc_list3.list_len = desc3->len; #endif ll_unitdesc_req->sapi = llc_data->current_sapi; ll_unitdesc_req->tlli = llc_data->u->current_tlli; /* * No attach to primitive necessary. For retransmission prim * data is copied in T200. */ ll_unitdesc_req->attached_counter = CCI_NO_ATTACHE; /* * LLC does not know the QoS profile. */ 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 */ u_build_u_frame ( #ifndef LL_DESC &ll_unitdesc_req->sdu, #else &ll_unitdesc_req->desc_list3, #endif MS_COMMAND, llc_data->current_sapi, 1, U_DISC ); /* * T200 has to be started _before_ the primitive is sent to TX, because * the primitive is copied by t200_start() and it may not be valid * anymore after sending to TX. */ sig_u_t200_start_req (ll_unitdesc_req, GRLC_DTACS_DEF); sig_u_tx_data_req (ll_unitdesc_req, GRLC_DTACS_DEF); } return; } /* u_send_disc() */ #ifdef REL99 /* +------------------------------------------------------------------------------ | Function : sig_tx_u_send_null +------------------------------------------------------------------------------ | Description : This procedure allocates a LL_UNITDATA_REQ primitive, fills in | the required parameters, builds an U frame header containing | an NULL command, and sends this primitive to TX. | | Parameters : cause - frame cause indicates grr about cell notification | +------------------------------------------------------------------------------ */ GLOBAL void sig_tx_u_send_null (UBYTE cause) { #ifdef LL_DESC T_desc3* desc3; #endif TRACE_FUNCTION( "sig_tx_u_send_null" ); { #ifndef LL_DESC PALLOC_SDU (ll_unitdesc_req, LL_UNITDATA_REQ, U_HDR_SIZE_BITS + FCS_SIZE_BITS); #else PALLOC (ll_unitdesc_req, LL_UNITDESC_REQ); desc3 = llc_palloc_desc((U_HDR_SIZE_BITS + FCS_SIZE_BITS)/8, 0); ll_unitdesc_req->desc_list3.first = (ULONG)desc3; ll_unitdesc_req->desc_list3.list_len = desc3->len; #endif /* * Set TLLI for current transaction. */ llc_data->u->current_tlli = llc_data->tlli_new; ll_unitdesc_req->sapi = llc_data->current_sapi; ll_unitdesc_req->tlli = llc_data->u->current_tlli; /* * No attach to primitive necessary. For retransmission prim * data is copied in T200. */ ll_unitdesc_req->attached_counter = CCI_NO_ATTACHE; /* * LLC does not know the QoS profile. */ ll_unitdesc_req->ll_qos.peak = GRLC_PEAK_SUB; /* * LLC signalling frames are always sent with highest priority. */ ll_unitdesc_req->radio_prio = GRLC_RADIO_PRIO_1; u_build_u_frame ( #ifndef LL_DESC &ll_unitdesc_req->sdu, #else &ll_unitdesc_req->desc_list3, #endif MS_COMMAND, llc_data->current_sapi, 0, U_NULL ); sig_u_tx_data_req (ll_unitdesc_req, cause); } return; } /* sig_tx_u_send_null() */ #endif /* REL99 */ /* +------------------------------------------------------------------------------ | Function : u_send_ua +------------------------------------------------------------------------------ | Description : This procedure allocates a LL_UNITDATA_REQ primitive, fills in | the required parameters, builds an U frame header containing | an UA response with the given pf_bit setting, and sends this | primitive to TX. The parameter include_xid indicates if an | XID information field (according to llc_xid_tag) shall be | included (=TRUE) or not. | | Parameters : pf_bit - setting of the P/F bit in the received command | include_xid - include XID information field in frame, or not | +------------------------------------------------------------------------------ */ GLOBAL void u_send_ua (T_BIT pf_bit, BOOL include_xid) { #ifdef LL_DESC T_desc3* desc3; #endif USHORT byte_len = 0; TRACE_FUNCTION( "u_send_ua" ); if (include_xid EQ TRUE) { u_tag_xid_parameters(1, TRUE); /* * Calculate bit length of tagged XID parameters. First, add * the size of each tagged parameter. The size of layer-3 * parameters is variable, so add the given length in octets. */ ADD_IF_TAGGED (byte_len, XID_VERSION); ADD_IF_TAGGED (byte_len, XID_T200); ADD_IF_TAGGED (byte_len, XID_N200); ADD_IF_TAGGED (byte_len, XID_N201_U); ADD_IF_TAGGED (byte_len, XID_N201_I); ADD_IF_TAGGED (byte_len, XID_MD); ADD_IF_TAGGED (byte_len, XID_MU); ADD_IF_TAGGED (byte_len, XID_KD); ADD_IF_TAGGED (byte_len, XID_KU); if (llc_data->u->xid_tag & (0x00000001L << XID_LAYER_3)) { byte_len += llc_data->requested_l3_xid->length + 2; } } /* * Add data header and FCS field to the XID response size to get * the overall data size. */ byte_len += U_HDR_SIZE + FCS_SIZE; { #ifndef LL_DESC PALLOC_SDU (ll_unitdesc_req, LL_UNITDATA_REQ, (USHORT)(byte_len*8)); #else PALLOC (ll_unitdesc_req, LL_UNITDESC_REQ); desc3 = llc_palloc_desc((USHORT)(byte_len), 0); ll_unitdesc_req->desc_list3.first = (ULONG)desc3; ll_unitdesc_req->desc_list3.list_len = desc3->len; #endif ll_unitdesc_req->sapi = llc_data->current_sapi; ll_unitdesc_req->tlli = llc_data->u->current_tlli; /* * No attach to primitive necessary. There is no retransmission. */ ll_unitdesc_req->attached_counter = CCI_NO_ATTACHE; /* * LLC does not know the QoS profile. */ 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 */ u_build_u_frame ( #ifndef LL_DESC &ll_unitdesc_req->sdu, #else &ll_unitdesc_req->desc_list3, #endif MS_RESPONSE, llc_data->current_sapi, pf_bit, U_UA ); if (include_xid EQ TRUE) { u_insert_xid ( #ifndef LL_DESC &ll_unitdesc_req->sdu, #else &ll_unitdesc_req->desc_list3, #endif MS_RESPONSE ); } sig_u_tx_data_req (ll_unitdesc_req, GRLC_DTACS_DEF); } llc_init_requested_xid_sapi(llc_data->current_sapi); return; } /* u_send_ua() */ /* +------------------------------------------------------------------------------ | Function : u_send_dm +------------------------------------------------------------------------------ | Description : This procedure allocates a LL_UNITDATA_REQ primitive, fills in | all required parameters, builds an U frame header containing a | DM response with the given pf_bit setting, and sends this | primitive to TX. | | Parameters : pf_bit - setting of the P/F bit in the received command | +------------------------------------------------------------------------------ */ GLOBAL void u_send_dm (T_BIT pf_bit) { #ifdef LL_DESC T_desc3* desc3; #endif TRACE_FUNCTION( "u_send_dm" ); { #ifndef LL_DESC PALLOC_SDU (ll_unitdesc_req, LL_UNITDATA_REQ, U_DM_SIZE_BITS + FCS_SIZE_BITS); #else PALLOC (ll_unitdesc_req, LL_UNITDESC_REQ); desc3 = llc_palloc_desc((U_DM_SIZE_BITS + FCS_SIZE_BITS)/8, 0); ll_unitdesc_req->desc_list3.first = (ULONG)desc3; ll_unitdesc_req->desc_list3.list_len = desc3->len; #endif ll_unitdesc_req->sapi = llc_data->current_sapi; ll_unitdesc_req->tlli = llc_data->u->current_tlli; /* * No attach to primitive necessary. There is no retransmission. */ ll_unitdesc_req->attached_counter = CCI_NO_ATTACHE; /* * LLC does not know the QoS profile. */ 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 */ u_build_u_frame ( #ifndef LL_DESC &ll_unitdesc_req->sdu, #else &ll_unitdesc_req->desc_list3, #endif MS_RESPONSE, llc_data->current_sapi, pf_bit, U_DM ); sig_u_tx_data_req (ll_unitdesc_req, GRLC_DTACS_DEF); } return; } /* u_send_dm() */ /* +------------------------------------------------------------------------------ | Function : u_send_frmr +------------------------------------------------------------------------------ | Description : This procedure allocates a LL_UNITDATA_REQ primitive, fills in | the required parameters, builds an U frame header containing | an FRMR response, fills in the FRMR information field based on | the given frame, vs, vr, the cr_bit setting of frame | (SGSN_COMMAND/REPONSE), and the reason of the frame rejection | condition (lower nibble conforms to W4-W1 in FRMR response). | This primitive is then sent to TX. | | Parameters : frame - frame that caused the frame rejection condition | pdu_type - frame type | ctrl_length - control field length, if known | vs - current V(S) | vr - current V(R) | cr_bit - setting of C/R bit in frame | reason - reason of the frame rejection condition (lower | nibble conforms to W4-W1 in FRMR response) | +------------------------------------------------------------------------------ */ GLOBAL void u_send_frmr (T_LL_UNITDATA_IND *frame, T_PDU_TYPE pdu_type, USHORT ctrl_length, T_FRAME_NUM vs, T_FRAME_NUM vr, T_BIT cr_bit, UBYTE reason) { #ifdef LL_DESC T_desc3* desc3; #endif TRACE_FUNCTION( "u_send_frmr" ); { #ifndef LL_DESC PALLOC_SDU (ll_unitdesc_req, LL_UNITDATA_REQ, U_FRMR_SIZE_BITS + FCS_SIZE_BITS); #else PALLOC (ll_unitdesc_req, LL_UNITDESC_REQ); desc3 = llc_palloc_desc((U_FRMR_SIZE_BITS + FCS_SIZE_BITS)/8, 0); ll_unitdesc_req->desc_list3.first = (ULONG)desc3; ll_unitdesc_req->desc_list3.list_len = desc3->len; #endif ll_unitdesc_req->sapi = llc_data->current_sapi; ll_unitdesc_req->tlli = llc_data->u->current_tlli; /* * No attach to primitive necessary. There is no retransmission. */ ll_unitdesc_req->attached_counter = CCI_NO_ATTACHE; /* * LLC does not know the QoS profile. */ 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 */ u_build_u_frame ( #ifndef LL_DESC &ll_unitdesc_req->sdu, #else &ll_unitdesc_req->desc_list3, #endif MS_RESPONSE, llc_data->current_sapi, 1, U_FRMR ); u_insert_frmr_information ( #ifndef LL_DESC &ll_unitdesc_req->sdu, #else &ll_unitdesc_req->desc_list3, #endif frame, pdu_type, ctrl_length, vs, vr, cr_bit, reason ); sig_u_tx_data_req (ll_unitdesc_req, GRLC_DTACS_DEF); } return; } /* u_send_frmr() */ /* +------------------------------------------------------------------------------ | Function : u_send_llgmm_status_ind +------------------------------------------------------------------------------ | Description : This procedure allocates an LLGMM_STATUS_IND primitive, fills | in the error_cause parameter, and sends this primitive to GMM. | | Parameters : error_cause - LLGMM error cause | +------------------------------------------------------------------------------ */ #ifdef CC_CONCEPT GLOBAL void u_send_llgmm_status_ind (USHORT error_cause) #else GLOBAL void u_send_llgmm_status_ind (UBYTE error_cause) #endif { TRACE_FUNCTION( "u_send_llgmm_status_ind" ); { PALLOC (llgmm_status_ind, LLGMM_STATUS_IND); /* T_LLGMM_STATUS_IND */ #ifdef LL_2to1 llgmm_status_ind->ps_cause.ctrl_value = CAUSE_is_from_llc; llgmm_status_ind->ps_cause.value.llc_cause = error_cause; #else llgmm_status_ind->error_cause = error_cause; #endif PSEND (hCommGMM, llgmm_status_ind); } return; } /* u_send_llgmm_status_ind() */ /* +------------------------------------------------------------------------------ | Function : u_send_ll_release_cnf +------------------------------------------------------------------------------ | Description : This procedure allocates an LL_RELEASE_CNF primitive, fills in | tlli and sapi parameters, and sends this primitive to SNDCP. | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_send_ll_release_cnf (void) { TRACE_FUNCTION( "u_send_ll_release_cnf" ); { PALLOC (ll_release_cnf, LL_RELEASE_CNF); ll_release_cnf->sapi = llc_data->current_sapi; TRACE_1_OUT_PARA("s:%d", llc_data->current_sapi ); PSEND (hCommSNDCP, ll_release_cnf); } llc_data->u->release_requested = FALSE; return; } /* u_send_ll_release_cnf() */ /* +------------------------------------------------------------------------------ | Function : u_send_ll_status_ind +------------------------------------------------------------------------------ | Description : This procedure allocates an LL_STATUS_IND primitive, fills in | tlli, sapi and cause parameters and sends this proimitive to L3 | | Parameters : cause - LL error cause | +------------------------------------------------------------------------------ */ #ifdef CC_CONCEPT GLOBAL void u_send_ll_status_ind (USHORT cause) #else GLOBAL void u_send_ll_status_ind (UBYTE cause) #endif { TRACE_FUNCTION( "u_send_ll_status_ind" ); { PALLOC (ll_status_ind, LL_STATUS_IND); ll_status_ind->sapi = llc_data->current_sapi; #ifdef LL_2to1 ll_status_ind->ps_cause.ctrl_value = CAUSE_is_from_llc; ll_status_ind->ps_cause.value.llc_cause = cause; #else ll_status_ind->error_cause = cause; #endif TRACE_1_OUT_PARA("s:%d", llc_data->current_sapi ); PSEND (hCommSNDCP, ll_status_ind); } return; } /* u_send_ll_status_ind() */ /* +------------------------------------------------------------------------------ | Function : u_send_ll_xid_cnf +------------------------------------------------------------------------------ | Description : This procedure allocates an LL_XID_CNF primitive, fills in | tlli, sapi and L3 parameter (if being negotiated), and sends | this primitive to SNDCP | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_send_ll_xid_cnf (void) { TRACE_FUNCTION( "u_send_ll_xid_cnf" ); if (llc_data->decoded_l3_xid.valid EQ TRUE) { PALLOC_SDU (ll_xid_cnf, LL_XID_CNF, (USHORT)(llc_data->decoded_l3_xid.length * 8)); ll_xid_cnf->sdu.l_buf = llc_data->decoded_l3_xid.length * 8; ll_xid_cnf->sdu.o_buf = 0; memcpy (ll_xid_cnf->sdu.buf, llc_data->decoded_l3_xid.value, llc_data->decoded_l3_xid.length); ll_xid_cnf->sapi = llc_data->current_sapi; ll_xid_cnf->n201_u = *(llc_data->n201_u); ll_xid_cnf->n201_i = *(llc_data->n201_i); TRACE_2_OUT_PARA("s:%d xid-len:%d", llc_data->current_sapi, llc_data->decoded_l3_xid.length ); PSEND (hCommSNDCP, ll_xid_cnf); } else { PALLOC_SDU (ll_xid_cnf, LL_XID_CNF, 0); ll_xid_cnf->sdu.l_buf = 0; ll_xid_cnf->sdu.o_buf = 0; ll_xid_cnf->sapi = llc_data->current_sapi; ll_xid_cnf->n201_u = *(llc_data->n201_u); ll_xid_cnf->n201_i = *(llc_data->n201_i); TRACE_2_OUT_PARA("s:%d xid-len:%d", llc_data->current_sapi, 0 ); PSEND (hCommSNDCP, ll_xid_cnf); } return; } /* u_send_ll_xid_cnf() */ /* +------------------------------------------------------------------------------ | Function : u_send_ll_establish_ind +------------------------------------------------------------------------------ | Description : This procedure allocates an LL_ESTABLISH_IND primitive, fills | in all necessary parameters using global LLC values (or in case | of L-3 XID parameters, using the parameters of received XID | cmd/res), and sends this primitive to SNDCP | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_send_ll_establish_ind (void) { USHORT len; TRACE_FUNCTION( "u_send_ll_establish_ind" ); if (llc_data->decoded_l3_xid.valid EQ TRUE) { len = (llc_data->decoded_l3_xid.length * 8); } else { len = 0; } { PALLOC_SDU (ll_establish_ind, LL_ESTABLISH_IND, len); if (llc_data->decoded_l3_xid.valid EQ TRUE) { ll_establish_ind->xid_valid = LL_XID_VALID; ll_establish_ind->sdu.o_buf = 0; ll_establish_ind->sdu.l_buf = llc_data->decoded_l3_xid.length * 8; memcpy (ll_establish_ind->sdu.buf, llc_data->decoded_l3_xid.value, llc_data->decoded_l3_xid.length); } else { ll_establish_ind->xid_valid = LL_XID_INVALID; } ll_establish_ind->sapi = llc_data->current_sapi; /* * evaluate N201_U */ if (llc_data->u->requested_xid.n201_u.valid AND llc_data->decoded_xid.n201_u.valid AND !llc_xid_value_acceptable (llc_data->current_sapi, XID_N201_U, llc_data->decoded_xid.n201_u.value)) { ll_establish_ind->n201_u = llc_data->u->requested_xid.n201_u.value; } else if (llc_data->u->requested_xid.n201_u.valid AND !llc_data->decoded_xid.n201_u.valid AND !llc_xid_value_acceptable (llc_data->current_sapi, XID_N201_U, *(llc_data->n201_u))) { ll_establish_ind->n201_u = llc_data->u->requested_xid.n201_u.value; } else { ll_establish_ind->n201_u = *(llc_data->n201_u); } /* * evaluate N201_I */ if (llc_data->u->requested_xid.n201_i.valid AND llc_data->decoded_xid.n201_i.valid AND !llc_xid_value_acceptable (llc_data->current_sapi, XID_N201_I, llc_data->decoded_xid.n201_i.value)) { ll_establish_ind->n201_i = llc_data->u->requested_xid.n201_i.value; } else if (llc_data->u->requested_xid.n201_i.valid AND !llc_data->decoded_xid.n201_i.valid AND !llc_xid_value_acceptable (llc_data->current_sapi, XID_N201_I, *(llc_data->n201_i))) { ll_establish_ind->n201_i = llc_data->u->requested_xid.n201_i.value; } else { ll_establish_ind->n201_i = *(llc_data->n201_i); } TRACE_2_OUT_PARA("s:%d xid-len:%d", ll_establish_ind->sapi, len/8); PSEND (hCommSNDCP, ll_establish_ind); return; } } /* u_send_ll_establish_ind() */ /* +------------------------------------------------------------------------------ | Function : u_send_ll_establish_cnf +------------------------------------------------------------------------------ | Description : This procedure allocates an LL_ESTABLISH_CNF primitive, fills | in all necessary parameters using global LLC values (or in case | of L-3 XID parameters, using the parameters of received XID | cmd/res), and sends this primitive to SNDCP | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_send_ll_establish_cnf (void) { TRACE_FUNCTION( "u_send_ll_establish_cnf" ); if (llc_data->decoded_l3_xid.valid EQ TRUE) { PALLOC_SDU (ll_establish_cnf, LL_ESTABLISH_CNF, (USHORT)(llc_data->decoded_l3_xid.length * 8)); ll_establish_cnf->xid_valid = LL_XID_VALID; ll_establish_cnf->sdu.o_buf = 0; ll_establish_cnf->sdu.l_buf = llc_data->decoded_l3_xid.length * 8; memcpy (ll_establish_cnf->sdu.buf, llc_data->decoded_l3_xid.value, llc_data->decoded_l3_xid.length); ll_establish_cnf->sapi = llc_data->current_sapi; ll_establish_cnf->n201_u = *(llc_data->n201_u); ll_establish_cnf->n201_i = *(llc_data->n201_i); TRACE_2_OUT_PARA("s:%d xid-len:%d", llc_data->current_sapi, llc_data->decoded_l3_xid.length ); PSEND (hCommSNDCP, ll_establish_cnf); } else { PALLOC_SDU (ll_establish_cnf, LL_ESTABLISH_CNF, 0); ll_establish_cnf->xid_valid = LL_XID_INVALID; ll_establish_cnf->sapi = llc_data->current_sapi; ll_establish_cnf->n201_u = *(llc_data->n201_u); ll_establish_cnf->n201_i = *(llc_data->n201_i); TRACE_2_OUT_PARA("s:%d xid-len:%d", llc_data->current_sapi, 0 ); PSEND (hCommSNDCP, ll_establish_cnf); } return; } /* u_send_ll_establish_cnf() */ /* +------------------------------------------------------------------------------ | Function : u_send_ll_release_ind +------------------------------------------------------------------------------ | Description : This procedure allocates an LL_RELEASE_IND primitive, fills | in tlli, sapi and cause parameters, and sends this primitive | to SNDCP | | Parameters : cause - LL error cause | +------------------------------------------------------------------------------ */ #ifdef CC_CONCEPT GLOBAL void u_send_ll_release_ind (USHORT cause) #else GLOBAL void u_send_ll_release_ind (UBYTE cause) #endif { TRACE_FUNCTION( "u_send_ll_release_ind" ); { PALLOC (ll_release_ind, LL_RELEASE_IND); ll_release_ind->sapi = llc_data->current_sapi; #ifdef LL_2to1 ll_release_ind->ps_cause.ctrl_value = CAUSE_is_from_llc; ll_release_ind->ps_cause.value.llc_cause = cause; #else ll_release_ind->cause = cause; #endif TRACE_1_OUT_PARA("s:%d", llc_data->current_sapi ); PSEND (hCommSNDCP, ll_release_ind); } llc_data->u->release_requested = FALSE; return; } /* u_send_ll_release_ind() */ /* +------------------------------------------------------------------------------ | Function : u_send_ll_xid_ind +------------------------------------------------------------------------------ | Description : This procedure allocates an LL_XID_IND primitive, fills | in all necessary parameters using global LLC values (or in case | of L-3 XID parameters, using the parameters of received XID | cmd/res), and sends this primitive to SNDCP | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_send_ll_xid_ind (void) { TRACE_FUNCTION( "u_send_ll_xid_ind" ); if (llc_data->decoded_l3_xid.valid EQ TRUE) { PALLOC_SDU (ll_xid_ind, LL_XID_IND, (USHORT)(llc_data->decoded_l3_xid.length * 8)); llc_data->u->ll_xid_resp_pending = TRUE; ll_xid_ind->xid_valid = LL_XID_VALID; ll_xid_ind->sdu.o_buf = 0; ll_xid_ind->sdu.l_buf = llc_data->decoded_l3_xid.length * 8; memcpy (ll_xid_ind->sdu.buf, llc_data->decoded_l3_xid.value, llc_data->decoded_l3_xid.length); ll_xid_ind->sapi = llc_data->current_sapi; if (llc_data->u->requested_xid.n201_u.valid AND !llc_xid_value_acceptable (llc_data->current_sapi, XID_N201_U, llc_data->decoded_xid.n201_u.value)) { ll_xid_ind->n201_u = llc_data->u->requested_xid.n201_u.value; } else { ll_xid_ind->n201_u = *(llc_data->n201_u); } switch (ll_xid_ind->sapi) { case LL_SAPI_3: case LL_SAPI_5: case LL_SAPI_9: case LL_SAPI_11: if (llc_data->u->requested_xid.n201_i.valid AND !llc_xid_value_acceptable (llc_data->current_sapi, XID_N201_I, llc_data->decoded_xid.n201_i.value)) { ll_xid_ind->n201_i = llc_data->u->requested_xid.n201_i.value; } else { ll_xid_ind->n201_i = *(llc_data->n201_i); } break; default: ll_xid_ind->n201_i = 0; break; } /* * Send primitive LL_XID_IND to either GMM, SNDCP, or GSMS, * depending on SAPI. */ switch (ll_xid_ind->sapi) { case LL_SAPI_1: TRACE_PRIM_TO("GMM"); TRACE_2_OUT_PARA("s:%d xid-len:%d", ll_xid_ind->sapi, llc_data->decoded_l3_xid.length); PSEND (hCommGMM, ll_xid_ind); break; case LL_SAPI_3: case LL_SAPI_5: case LL_SAPI_9: case LL_SAPI_11: TRACE_2_OUT_PARA("s:%d xid-len:%d", ll_xid_ind->sapi, llc_data->decoded_l3_xid.length); PSEND (hCommSNDCP, ll_xid_ind); break; case LL_SAPI_7: #ifdef LL_2to1 TRACE_PRIM_TO("MM"); TRACE_2_OUT_PARA("s:%d xid-len:%d", ll_xid_ind->sapi, llc_data->decoded_l3_xid.length); PSEND (hCommMM, ll_xid_ind); #else TRACE_PRIM_TO("GSMS"); TRACE_2_OUT_PARA("s:%d xid-len:%d", ll_xid_ind->sapi, llc_data->decoded_l3_xid.length); PSEND (hCommGSMS, ll_xid_ind); #endif break; default: PFREE (ll_xid_ind); TRACE_ERROR ("Invalid global SAPI value"); break; } } else { PALLOC_SDU (ll_xid_ind, LL_XID_IND, 0); llc_data->u->ll_xid_resp_pending = FALSE; ll_xid_ind->xid_valid = LL_XID_INVALID; ll_xid_ind->sapi = llc_data->current_sapi; ll_xid_ind->n201_u = *(llc_data->n201_u); switch (ll_xid_ind->sapi) { case LL_SAPI_3: case LL_SAPI_5: case LL_SAPI_9: case LL_SAPI_11: ll_xid_ind->n201_i = *(llc_data->n201_i); break; default: ll_xid_ind->n201_i = 0; break; } /* * Send primitive LL_XID_IND to either GMM, SNDCP, or GSMS, * depending on SAPI. */ switch (ll_xid_ind->sapi) { case LL_SAPI_1: TRACE_PRIM_TO("GMM"); TRACE_1_OUT_PARA("s:%d no l3-xid", ll_xid_ind->sapi); PSEND (hCommGMM, ll_xid_ind); break; case LL_SAPI_3: case LL_SAPI_5: case LL_SAPI_9: case LL_SAPI_11: TRACE_1_OUT_PARA("s:%d no l3-xid", ll_xid_ind->sapi); PSEND (hCommSNDCP, ll_xid_ind); break; case LL_SAPI_7: #ifdef LL_2to1 TRACE_PRIM_TO("MM"); TRACE_1_OUT_PARA("s:%d no l3-xid", ll_xid_ind->sapi); PSEND (hCommMM, ll_xid_ind); #else TRACE_PRIM_TO("GSMS"); TRACE_1_OUT_PARA("s:%d no l3-xid", ll_xid_ind->sapi); PSEND (hCommGSMS, ll_xid_ind); #endif break; default: PFREE (ll_xid_ind); TRACE_ERROR ("invalid global SAPI value"); break; } } return; } /* u_send_ll_xid_ind() */ /* +------------------------------------------------------------------------------ | Function : u_tag_xid_parameters +------------------------------------------------------------------------------ | Description : This procedure tags requested parameters | | | Parameters : | - send_ack_para- used to include/ignore the ack para in XID-FRAME | +------------------------------------------------------------------------------ */ GLOBAL void u_tag_xid_parameters (T_BIT cr_bit, BOOL send_ack_para) { TRACE_FUNCTION( "u_tag_xid_parameters" ); if (cr_bit EQ MS_RESPONSE) { /* * Do some special handling in case we want to set mD or mU to zero * (= disable buffered bytes counting) and the peer does not. */ if (llc_data->decoded_xid.mu.valid) { u_handle_mX_zero_rsp ( llc_data->decoded_xid.mu.value, llc_data->n201_i, *(llc_data->mu), XID_MU_MAX, llc_data->ku, XID_KU_MIN, XID_KU ); } if (llc_data->decoded_xid.md.valid) { u_handle_mX_zero_rsp ( llc_data->decoded_xid.md.value, llc_data->n201_i, *(llc_data->md), XID_MD_MAX, llc_data->kd, XID_KD_MIN, XID_KD ); } } /* * Tag all possible requested XID parameter */ if (cr_bit EQ MS_COMMAND) { /* * In case we are sending a command, we can include all * parameters, as long they are valid. */ TAG_IF_REQUESTED (u->requested_xid.version. , XID_VERSION); TAG_IF_REQUESTED (u->requested_xid.t200. , XID_T200); TAG_IF_REQUESTED (u->requested_xid.n200. , XID_N200); TAG_IF_REQUESTED (u->requested_xid.n201_u. , XID_N201_U); TAG_IF_REQUESTED (requested_l3_xid-> , XID_LAYER_3); if(send_ack_para) { TRACE_EVENT("COMMAND: ACK MODE PARAMETERS INCLUDED"); TAG_IF_REQUESTED (u->requested_xid.n201_i. , XID_N201_I); TAG_IF_REQUESTED (u->requested_xid.md. , XID_MD); TAG_IF_REQUESTED (u->requested_xid.mu. , XID_MU); TAG_IF_REQUESTED (u->requested_xid.kd. , XID_KD); TAG_IF_REQUESTED (u->requested_xid.ku. , XID_KU); } else { llc_data->u->requested_xid.n201_i.valid = FALSE; llc_data->u->requested_xid.md.valid = FALSE; llc_data->u->requested_xid.mu.valid = FALSE; llc_data->u->requested_xid.kd.valid = FALSE; llc_data->u->requested_xid.ku.valid = FALSE; } } else { /* * In case we are sending a response, we can include all valid * parameters which are in line with the sense of negotiation. */ TAG_IF_REQUESTED_RSP (XID_SENSE_UP, n200, XID_N200); TAG_IF_REQUESTED_RSP (XID_SENSE_DOWN, n201_u, XID_N201_U); if(send_ack_para) { TRACE_EVENT("RESPONSE: ACK MODE PARAMETERS INCLUDED"); TAG_IF_REQUESTED_RSP (XID_SENSE_DOWN, n201_i, XID_N201_I); TAG_IF_REQUESTED_RSP (XID_SENSE_DOWN, md, XID_MD); TAG_IF_REQUESTED_RSP (XID_SENSE_DOWN, mu, XID_MU); TAG_IF_REQUESTED_RSP (XID_SENSE_DOWN, kd, XID_KD); TAG_IF_REQUESTED_RSP (XID_SENSE_DOWN, ku, XID_KU); } if (llc_data->u->requested_xid.t200.valid) { if (llc_data->decoded_xid.t200.valid) { /* simple add parameter. Sense of negotiation is already checked */ llc_data->u->xid_tag |= (0x00000001L << XID_T200); } else { /* Sense of negotiation compared with current values */ if (llc_data->u->requested_xid.t200.value XID_SENSE_UP INT2XID(llc_data->t200->length)) { llc_data->u->xid_tag |= (0x00000001L << XID_T200); } } } /* * L3 parameter cannot be included in response, if not included in * request */ /* * If an XID parameter which was not included in the SGSN command, * but included in the MS Response, must be included in every Response * until the parameter is explicitly negotiated by the SGSN */ if(llc_data->u->xid_tag_negotiate) { llc_data->u->xid_tag |= llc_data->u->xid_tag_negotiate; } } } /* u_tag_xid_parameters() */ /* +------------------------------------------------------------------------------ | Function : u_send_xid +------------------------------------------------------------------------------ | Description : This procedure allocates a LL_UNITDATA_REQ primitive, fills in | the required parameters, builds an U frame header containing an | XID command/response (depending on the cr_bit setting), inserts | all XID parmameters that are to be negotiated, and sends this | primitive to TX. If a command frame is being sent (see cr_bit), | T200 has to be started _before_ the primitive is sent to TX, | because otherwise the primitive may not be valid anymore. | | NOTE: T200 must not be running, when an XID command is to be | sent. This must be ensured by the caller of u_send_xid(). | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_send_xid (T_BIT cr_bit) { #ifdef LL_DESC T_desc3* desc3; #endif USHORT byte_len = 0; TRACE_FUNCTION( "u_send_xid" ); /* * Calculate bit length of tagged XID parameters. First, add * the size of each tagged parameter. The size of layer-3 * parameters is variable, so add the given length in octets. */ ADD_IF_TAGGED (byte_len, XID_VERSION); ADD_IF_TAGGED (byte_len, XID_T200); ADD_IF_TAGGED (byte_len, XID_N200); ADD_IF_TAGGED (byte_len, XID_N201_U); /*Acknowledge Mode Parameters will be ignored in XID FRAME: ADD_IF_TAGGED (byte_len, XID_N201_I); ADD_IF_TAGGED (byte_len, XID_MD); ADD_IF_TAGGED (byte_len, XID_MU); ADD_IF_TAGGED (byte_len, XID_KD); ADD_IF_TAGGED (byte_len, XID_KU); */ if (llc_data->u->xid_tag & (0x00000001L << XID_LAYER_3)) { byte_len += llc_data->requested_l3_xid->length + 2; } /* * Add data header and FCS field to the XID response size to get * the overall data size. */ byte_len += U_HDR_SIZE + FCS_SIZE; { #ifndef LL_DESC PALLOC_SDU (ll_unitdesc_req, LL_UNITDATA_REQ, (USHORT)(byte_len*8)); #else PALLOC (ll_unitdesc_req, LL_UNITDESC_REQ); desc3 = llc_palloc_desc(byte_len, 0); ll_unitdesc_req->desc_list3.first = (ULONG)desc3; ll_unitdesc_req->desc_list3.list_len = desc3->len; #endif ll_unitdesc_req->sapi = llc_data->current_sapi; ll_unitdesc_req->tlli = llc_data->tlli_new; /* * LLC does not know the QoS profile. */ 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 */ /* * No attach to primitive necessary. For retransmission prim * data is copied in T200 (if requested). */ ll_unitdesc_req->attached_counter = CCI_NO_ATTACHE; /* * Label U_SEND_XID_CONT */ /* * pf_bit must always be 1 when XID cmd/res are being sent */ u_build_u_frame ( #ifndef LL_DESC &ll_unitdesc_req->sdu, #else &ll_unitdesc_req->desc_list3, #endif cr_bit, llc_data->current_sapi, 1, U_XID ); u_insert_xid ( #ifndef LL_DESC &ll_unitdesc_req->sdu, #else &ll_unitdesc_req->desc_list3, #endif cr_bit ); if (cr_bit EQ MS_COMMAND) { /* * remember that an XID command is currently being sent */ llc_data->u->xid_pending = TRUE; /* * T200 has to be started !before! the primitive is sent to TX. */ sig_u_t200_start_req (ll_unitdesc_req, GRLC_DTACS_DEF); } /* * U frames are always sent with default cause */ sig_u_tx_data_req (ll_unitdesc_req, GRLC_DTACS_DEF); } if (cr_bit EQ MS_RESPONSE) { llc_init_requested_xid_sapi(llc_data->current_sapi); } return; } /* u_send_xid() */ /* +------------------------------------------------------------------------------ | Function : u_handle_optimization +------------------------------------------------------------------------------ | Description : This procedure adds the values of the requested XID parameter | to the decoded XID structure, if they are not included (as an | optimization issue). | | Parameters : | +------------------------------------------------------------------------------ */ GLOBAL void u_handle_optimization (void) { TRACE_FUNCTION ("u_handle_optimization"); if (llc_data->u->xid_tag_sent & (0x00000001L << XID_VERSION) AND llc_data->decoded_xid.version.valid == FALSE ) { llc_data->decoded_xid.version.valid = TRUE; llc_data->decoded_xid.version.value = llc_data->u->requested_xid.version.valid ? llc_data->u->requested_xid.version.value : llc_data->version; } if (llc_data->u->xid_tag_sent & (0x00000001L << XID_T200) AND llc_data->decoded_xid.t200.valid == FALSE ) { llc_data->decoded_xid.t200.valid = TRUE; llc_data->decoded_xid.t200.value = llc_data->u->requested_xid.t200.valid ? llc_data->u->requested_xid.t200.value : ((USHORT)INT2XID (llc_data->t200->length)); } if (llc_data->u->xid_tag_sent & (0x00000001L << XID_N200) AND llc_data->decoded_xid.n200.valid == FALSE ) { llc_data->decoded_xid.n200.valid = TRUE; llc_data->decoded_xid.n200.value = llc_data->u->requested_xid.n200.valid ? llc_data->u->requested_xid.n200.value : *(llc_data->n200); } if (llc_data->u->xid_tag_sent & (0x00000001L << XID_N201_U) AND llc_data->decoded_xid.n201_u.valid == FALSE ) { llc_data->decoded_xid.n201_u.valid = TRUE; llc_data->decoded_xid.n201_u.value = llc_data->u->requested_xid.n201_u.valid ? llc_data->u->requested_xid.n201_u.value : *(llc_data->n201_u); } if (llc_data->u->xid_tag_sent & (0x00000001L << XID_N201_I) AND llc_data->decoded_xid.n201_i.valid == FALSE ) { llc_data->decoded_xid.n201_i.valid = TRUE; llc_data->decoded_xid.n201_i.value = llc_data->u->requested_xid.n201_i.valid ? llc_data->u->requested_xid.n201_i.value : *(llc_data->n201_i); } if (llc_data->u->xid_tag_sent & (0x00000001L << XID_MD) AND llc_data->decoded_xid.md.valid == FALSE ) { llc_data->decoded_xid.md.valid = TRUE; llc_data->decoded_xid.md.value = llc_data->u->requested_xid.md.valid ? llc_data->u->requested_xid.md.value : *(llc_data->md); } if (llc_data->u->xid_tag_sent & (0x00000001L << XID_MU) AND llc_data->decoded_xid.mu.valid == FALSE ) { llc_data->decoded_xid.mu.valid = TRUE; llc_data->decoded_xid.mu.value = llc_data->u->requested_xid.mu.valid ? llc_data->u->requested_xid.mu.value : *(llc_data->mu); } if (llc_data->u->xid_tag_sent & (0x00000001L << XID_KD) AND llc_data->decoded_xid.kd.valid == FALSE ) { llc_data->decoded_xid.kd.valid = TRUE; llc_data->decoded_xid.kd.value = llc_data->u->requested_xid.kd.valid ? llc_data->u->requested_xid.kd.value : *(llc_data->kd); } if (llc_data->u->xid_tag_sent & (0x00000001L << XID_KU) AND llc_data->decoded_xid.ku.valid == FALSE ) { llc_data->decoded_xid.ku.valid = TRUE; llc_data->decoded_xid.ku.value = llc_data->u->requested_xid.ku.valid ? llc_data->u->requested_xid.ku.value : *(llc_data->ku); } /* * Layer 3 XID must be included in resonse, if it was included in request */ } /* u_handle_optimization() */