diff src/g23m-gprs/llc/llc_uf.c @ 183:219afcfc6250

src/g23m-gprs: initial import from TCS3.2/LoCosto
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 13 Oct 2016 04:24:13 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/g23m-gprs/llc/llc_uf.c	Thu Oct 13 04:24:13 2016 +0000
@@ -0,0 +1,4152 @@
+  /*
++-----------------------------------------------------------------------------
+|  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() */
+
+