view src/g23m-gprs/sndcp/sndcp_cias.c @ 192:4f40ae165be4

abb.c & init.c: sync with Magnetite for Luna additions These Luna target-specific additions are conditionalized on CONFIG_TARGET_LUNA, a C preprocessor symbol that will never be defined in Selenite, hence this change has exactly zero impact on FC Selenite. However, they are being pulled in as a sync in order to keep the diff between Magnetite and Selenite to a minimum; keeping this diff to a minimum increases our opportunities for possible evolution of future FC firmwares.
author Mychaela Falconia <falcon@freecalypso.org>
date Sat, 23 May 2020 07:03:46 +0000
parents d393cd9bb723
children
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :  GPRS (8441)
|  Modul   :  sndcp_cias.c
+-----------------------------------------------------------------------------
|  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.
|
|  These files implement Van Jacobson Compression algorithm which is taken from
|  University of California Berkley's Implementation.
|
|
|  "Copyright (c)1989 Regents of the University of California.
|  All rights reserved.Redistribution and use in source and binary forms are
|  permitted, provided that the above  copyright notice and this paragraph are
|  duplicated in all such forms and that any documentation advertising materials,
|  and  other materials related to such distributionand use acknowledge that the
|  software was developed by the University of California, Berkeley.
|  The name of the University may not be  used to endorse or promote products
|  derived from this software without specific  prior written permission. 
|  THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|  INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND 
|  FITNESS FOR A PARTICULAR PURPOSE"
+-----------------------------------------------------------------------------
|  Purpose :  This modul is part of the entity SNDCP and implements all
|             functions to handles the incoming process internal signals as
|             described in the SDL-documentation (CIA-statemachine)
+-----------------------------------------------------------------------------
*/


#define ENTITY_SNDCP

/*==== INCLUDES =============================================================*/

#include "typedefs.h"    /* to get Condat data types */
#include "vsi.h"         /* to get a lot of macros */
#include "macdef.h"
#include "gsm.h"         /* to get a lot of macros */
#include "prim.h"        /* to get the definitions of used SAP and directions */

#include "dti.h"

#include "sndcp.h"       /* to get the global entity definitions */
#include "sndcp_f.h"     /* to get the functions to access the global arrays*/

#include <string.h>      /* to get memcpy() */
#include "sndcp_cias.h"  /* to get the signals to service cia */
#include "sndcp_ciap.h"  /* to get primitives to service cia */
#include "sndcp_ciaf.h"  /* to get primitives to service cia */
#include "sndcp_sdf.h"   /* to get sd functions */
#include "sndcp_sdaf.h"  /* to get sda functions */
#include "sndcp_sds.h"   /* to get sd signals */

#ifdef TI_PS_FF_V42BIS
#include "v42b_type.h"
#include "v42b_dico.h"
#include "v42b_enc.h"
#include "v42b_dec.h"
#include "v42b_debug.h"
#endif /* TI_PS_FF_V42BIS */

/*==== CONST ================================================================*/

/*==== LOCAL VARS ===========================================================*/

/*==== PRIVATE FUNCTIONS ====================================================*/

/*
 * Update connection state cs & send uncompressed packet ('uncompressed'
 * means a regular ip/tcp packet but with the 'conversation id' we hope
 * to use on future compressed packets in the protocol field).
 */
#define UNCOMPRESSED {\
  memcpy(cs->cs_hdr, (UBYTE*)cbuf->c_hdr, tip_hlen);\
  ip->ip_p = cs->cs_id;\
  sndcp_data->cia.comp.last_xmit = cs->cs_id;\
}


/*
+------------------------------------------------------------------------------
| Function    : cia_vj_comp
+------------------------------------------------------------------------------
| Description : compresses the TCP/IP header of the given packet
|               (Van Jacobson algorithm). A part of this routine has been taken
|               from implementation of University of California, Berkeley.
|
| Parameters  : com_buf - received packet, packet length, packet type
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

LOCAL UBYTE cia_vj_comp(struct comp_buf *cbuf)
{
  struct cstate            *cs  = sndcp_data->cia.comp.last_cs->cs_next;
  T_SNDCP_TCP_HEADER       *oth, *oth_tmp;     /* last TCP header */
  T_SNDCP_TCP_HEADER       *th;                /* current TCP header */
  T_SNDCP_IP_HEADER        *ip;                /* current IP header */
  USHORT                   ip_hlen, tip_hlen;  /* IP hdr len., TCP/IP hdr len*/
  USHORT                   tmp1, tmp2;         /* general purpose tempories */
  ULONG                    changes = 0;        /* change mask */
  UBYTE                    new_seq[16];       /* changes from last to current*/
  UBYTE                    *cp = new_seq;
  UBYTE                    th_off, oth_off;
  BOOL                     found = FALSE;
  USHORT                   th_sum;
  ULONG                    seq, o_seq;

  ip      = (T_SNDCP_IP_HEADER *)cbuf->c_hdr;
  ip_hlen = ip->ip_vhl & HL_MASK;            /* IP header length in integers */
  th      = (T_SNDCP_TCP_HEADER *)&((ULONG *)cbuf->c_hdr)[ip_hlen];
  th_off  = th->th_off >> 4;

  TRACE_FUNCTION( "cia_vj_comp" );

  /*
   * Bail if this is an IP fragment or if the TCP packet isn't
   * `compressible' (i.e., ACK isn't set or some other control bit is
   * set).  (We assume that the caller has already made sure the
   * packet is IP proto TCP).
   */
  if (ip->ip_off & 0xff3f)
  {
    TRACE_EVENT("INFO COMP: return TYPE_IP, packet is an IP fragment");
    return (TYPE_IP);
  }

  if ((th->th_flags & (TH_SYN|TH_FIN|TH_RST|TH_ACK)) != TH_ACK)
  {
    TRACE_EVENT("INFO COMP: return TYPE_IP, TH_ACK is not set");
    return (TYPE_IP);
  }
  /*
   * Packet is compressible -- we're going to send either a
   * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need
   * to locate (or create) the connection state.  Special case the
   * most recently used connection since it's most likely to be used
   * again & we don't have to do any reordering if it's used.
   */
  oth_tmp  = (T_SNDCP_TCP_HEADER *)
             &((ULONG *)cs->cs_hdr)[cs->cs_ip->ip_vhl & HL_MASK];
  if ((ip->ip_src   != cs->cs_ip->ip_src) ||
      (ip->ip_dst   != cs->cs_ip->ip_dst) ||
      (*(ULONG *)th != *(ULONG *)oth_tmp)){
    /*
     * Wasn't the first -- search for it.
     *
     * States are kept in a circularly linked list with
     * last_cs pointing to the end of the list.  The
     * list is kept in lru order by moving a state to the
     * head of the list whenever it is referenced.  Since
     * the list is short and, empirically, the connection
     * we want is almost always near the front, we locate
     * states via linear search.  If we don't find a state
     * for the datagram, the oldest state is (re-)used.
     */
    struct cstate *lcs;
    struct cstate *lastcs = sndcp_data->cia.comp.last_cs;

    do {
      lcs = cs;
      cs = cs->cs_next;
      oth_tmp  = (T_SNDCP_TCP_HEADER *)
                 &((ULONG *)cs->cs_hdr)[cs->cs_ip->ip_vhl & HL_MASK];
      if ((ip->ip_src   == cs->cs_ip->ip_src) &&
          (ip->ip_dst   == cs->cs_ip->ip_dst) &&
          (*(ULONG *)th == *(ULONG *)oth_tmp)){
        found = TRUE;
        break;
      }

    } while (cs != lastcs);

    if(found)
    {
      /*
       * Found it -- move to the front on the connection list.
       */
      if (cs == lastcs)
        sndcp_data->cia.comp.last_cs = lcs;
      else {
        lcs->cs_next = cs->cs_next;
        cs->cs_next = lastcs->cs_next;
        lastcs->cs_next = cs;
      }
    } else {
      /*
       * Didn't find it -- re-use oldest cstate.  Send an
       * uncompressed packet that tells the other side what
       * connection number we're using for this conversation.
       * Note that since the state list is circular, the oldest
       * state points to the newest and we only need to set
       * last_cs to update the lru linkage.
       */
      sndcp_data->cia.comp.last_cs = lcs;
      tip_hlen = (ip_hlen+th_off)<<2;
      UNCOMPRESSED;
      return (TYPE_UNCOMPRESSED_TCP);
    }/*if din't find*/
  }

  /*
   * Make sure that only what we expect to change changed. The first
   * line of the `if' checks the IP protocol version, header length &
   * type of service.  The 2nd line checks the "Don't fragment" bit.
   * The 3rd line checks the time-to-live and protocol (the protocol
   * check is unnecessary but costless).  The 4th line checks the TCP
   * header length.  The 5th line checks IP options, if any.  The 6th
   * line checks TCP options, if any.  If any of these things are
   * different between the previous & current datagram, we send the
   * current datagram `uncompressed'.
   */
  oth = (T_SNDCP_TCP_HEADER *)&((ULONG *)cs->cs_ip)[ip_hlen];
  oth_off  = oth->th_off >> 4;
  tip_hlen = (ip_hlen+th_off)<<2;

  if (((USHORT *)ip)[0] != ((USHORT *)cs->cs_ip)[0] ||
      ((USHORT *)ip)[3] != ((USHORT *)cs->cs_ip)[3] ||
      ((USHORT *)ip)[4] != ((USHORT *)cs->cs_ip)[4] ||
      (th_off           != oth_off)                 ||
      ((ip_hlen > 5) && (memcmp(ip + 1, cs->cs_ip + 1, (ip_hlen - 5) << 2))) ||
      ((th_off  > 5) && (memcmp(th + 1, oth + 1, (th_off - 5) << 2)))) {

    UNCOMPRESSED;
    return (TYPE_UNCOMPRESSED_TCP);
  }

  /*
   * Figure out which of the changing fields changed.  The
   * receiver expects changes in the order: urgent, window,
   * ack, seq (the order minimizes the number of temporaries
   * needed in this section of code).
   */
  if (th->th_flags & TH_URG) {
    tmp1 = sndcp_swap2(th->th_urp);
    if (tmp1 >= 256 || tmp1 == 0) {
      *cp++ = 0;
      cp[1] = (UBYTE)tmp1;
      cp[0] = (tmp1 & 0xff00) >> 8;
      cp += 2;
    } else {
      *cp++ = (UBYTE)tmp1;
    }
    changes |= NEW_U;
  } else if (th->th_urp != oth->th_urp){
    /* argh! URG not set but urp changed -- a sensible
     * implementation should never do this but RFC793
     * doesn't prohibit the change so we have to deal
     * with it. */
    UNCOMPRESSED;
    return (TYPE_UNCOMPRESSED_TCP);
  }
  if ((tmp1 = sndcp_swap2(th->th_win) - sndcp_swap2(oth->th_win)) != 0) {
    if (tmp1 >= 256) {
      *cp++ = 0;
      cp[1] = (UBYTE)tmp1;
      cp[0] = (tmp1 & 0xff00) >> 8;
      cp += 2;
    } else {
      *cp++ = (UBYTE)tmp1;
    }
    changes |= NEW_W;
  }

  if ((tmp2 = (USHORT)(sndcp_swap4(th->th_ack)-sndcp_swap4(oth->th_ack)))!=0){
    if (tmp2 > MAX_CHANGE){
      UNCOMPRESSED;
      return (TYPE_UNCOMPRESSED_TCP);
    }
    if (tmp2 >= 256) {
      *cp++ = 0;
      cp[1] = (UBYTE)tmp2;
      cp[0] = (tmp2 & 0xff00) >> 8;
      cp += 2;
    } else {
      *cp++ = (UBYTE)tmp2;
    }
    changes |= NEW_A;
  }

  seq   = sndcp_swap4(th->th_seq);
  o_seq = sndcp_swap4(oth->th_seq);
  if(seq < o_seq) {
    TRACE_EVENT("WARNING COMP: seq < o_seq, return UNCOMPRESSED_TCP ");
    UNCOMPRESSED;
    return (TYPE_UNCOMPRESSED_TCP);
  } else if((tmp1 = (USHORT)(seq - o_seq)) != 0) {
    if (tmp1 > MAX_CHANGE){
      UNCOMPRESSED;
      return (TYPE_UNCOMPRESSED_TCP);
    }
    if (tmp1 >= 256) {
      *cp++ = 0;
      cp[1] = (UBYTE)tmp1;
      cp[0] = (tmp1 & 0xff00) >> 8;
      cp += 2;
    } else {
      *cp++ = (UBYTE)tmp1;
    }
    changes |= NEW_S;
  }

  /* look for special case encodings. */
  switch (changes) {

  case 0:
    /*
     * Nothing changed. If this packet contains data and the
     * last one didn't, this is probably a data packet following
     * an ack (normal on an interactive connection) and we send
     * it compressed.  Otherwise it's probably a retransmit,
     * retransmitted ack or window probe.  Send it uncompressed
     * in case the other side missed the compressed version.
     */
    if ((ip->ip_len != cs->cs_ip->ip_len) &&
        (sndcp_swap2(cs->cs_ip->ip_len) == tip_hlen))
      break;

    /* (fall through) */

  case SPECIAL_I:
  case SPECIAL_D:
    /*
     * actual changes match one of our special case encodings --
     * send packet uncompressed.
     */
    UNCOMPRESSED;
    return (TYPE_UNCOMPRESSED_TCP);

  case NEW_S|NEW_A:
    if ((tmp1 == tmp2) &&
        (tmp1 == sndcp_swap2(cs->cs_ip->ip_len) - tip_hlen)) {
      /* special case for echoed terminal traffic */
      changes = SPECIAL_I;
      cp = new_seq;
    }
    break;

  case NEW_S:
    if (tmp1 == sndcp_swap2(cs->cs_ip->ip_len) - tip_hlen) {
      /* special case for data xfer */
      changes = SPECIAL_D;
      cp = new_seq;
    }
    break;
  }

  tmp1 = sndcp_swap2(ip->ip_id) - sndcp_swap2(cs->cs_ip->ip_id);
  if (tmp1 != 1) {
    if ((tmp1 >= 256) || (tmp1 == 0)) {
      *cp++ = 0;
      cp[1] = (UBYTE)tmp1;
      cp[0] = (tmp1 & 0xff00) >> 8;
      cp += 2;
    } else {
      *cp++ = (UBYTE)tmp1;
    }
    changes |= NEW_I;
  }

  if (th->th_flags & TH_PUSH)
    changes |= TCP_PUSH_BIT;
  /*
   * Grab the cksum before we overwrite it below.  Then update our
   * state with this packet's header.
   */
  th_sum = sndcp_swap2(th->th_sum);
  memcpy(cs->cs_ip, ip, tip_hlen);

  /*
   * We want to use the original packet as our compressed packet.
   * (cp - new_seq) is the number of bytes we need for compressed
   * sequence numbers.  In addition we need one byte for the change
   * mask, one for the connection id and two for the tcp checksum.
   * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how
   * many bytes of the original packet to toss so subtract the two to
   * get the new packet size.
   */
  tmp1 = cp - new_seq;
  cp = (UBYTE *)ip;

  /*
   * we always send a "new" connection id so the receiver state
   * stays synchronized.
   */
  sndcp_data->cia.comp.last_xmit = cs->cs_id;
  tip_hlen -= tmp1 + 4;
  cp       += tip_hlen;
  *cp++ = (UBYTE)(changes | NEW_C);
  *cp++ = cs->cs_id;

  cbuf->pack_len -= tip_hlen;
  cbuf->hdr_len  -= tip_hlen;
  cbuf->c_hdr    += tip_hlen;
  *cp++ = th_sum >> 8;
  *cp++ = (UBYTE)(th_sum & 0x00ff);
  memcpy(cp, new_seq, tmp1);
  return (TYPE_COMPRESSED_TCP);
}

#endif /* CF_FAST_EXEC */


/*
+------------------------------------------------------------------------------
| Function    : cia_header_comp
+------------------------------------------------------------------------------
| Description : compresses the TCP/IP header of the given packet
|               (Van Jacobson algorithm)
|
| Parameters  : packet as desc_list, packet_type.
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

#ifdef _SNDCP_DTI_2_
GLOBAL void cia_header_comp (T_desc_list2* dest_desc_list,
                                T_desc_list2* src_desc_list,
                                UBYTE* packet_type)
#else /*_SNDCP_DTI_2_*/
GLOBAL void cia_header_comp (T_desc_list* dest_desc_list,
                                T_desc_list* src_desc_list,
                                UBYTE* packet_type)
#endif /*_SNDCP_DTI_2_*/
{

#ifdef _SNDCP_DTI_2_
  T_desc2* src_desc = (T_desc2*)src_desc_list->first;
  T_desc2* new_desc;
  U8 *src_desc_buff = &src_desc->buffer[src_desc->offset];
#else /*_SNDCP_DTI_2_*/
  T_desc*  src_desc = (T_desc*)src_desc_list->first;
  T_desc*  new_desc;
  U8 *src_desc_buff = &src_desc->buffer[0];
#endif /*_SNDCP_DTI_2_*/


/*
 * A struct mbuf is used in the call cia_vj_comp because that routine
 * needs to modify both the start address and length if the incoming
 * packet is compressed
 */

  struct comp_buf           cbuf;
  T_SNDCP_IP_HEADER         *ip;
  T_SNDCP_TCP_HEADER        *tcp;
  USHORT                    hdr_len;
  USHORT                    offset;

  TRACE_FUNCTION( "cia_header_comp" );

  if ((src_desc == NULL))
  {
    TRACE_EVENT("ERROR: Descriptor Pointer is a NULLPTR");
    *packet_type = TYPE_ERROR;
    return;
  }

  /*
   * Verify protocol type and header length
   */
  ip = (T_SNDCP_IP_HEADER *)&src_desc_buff[0];
  if((ip->ip_p == PROT_TCPIP))
  {
    hdr_len  = (ip->ip_vhl & HL_MASK) << 2;
    tcp      = (T_SNDCP_TCP_HEADER *)&src_desc_buff[hdr_len];
    hdr_len += (tcp->th_off >> 4) << 2;
    if( (src_desc->len >= hdr_len) && (hdr_len >=40) ){
      /*
       * initialize comp_buf
       */
      cbuf.hdr_len  = hdr_len;       /* header len. passed to compr. routine*/
      cbuf.pack_len = src_desc->len; /* descriptor length */
      cbuf.p_type   = TYPE_IP;       /* set default packet type */
      /* use temporary buffer to store TCP/IP header */
      cbuf.c_hdr    = (ULONG)&sndcp_data->cia.comp.tcpip_hdr[0];
      memcpy((UBYTE*)cbuf.c_hdr, &src_desc_buff[0], cbuf.hdr_len);
      /*
       * Call VJ header compression routine
       */
      *packet_type = cia_vj_comp(&cbuf);
    }
    else
      *packet_type = TYPE_IP;

  }/* if TCP_IP_PROTOKOL */
  else{
    *packet_type = TYPE_IP;
    if(src_desc->len <40)
      TRACE_EVENT("INFO COMP: Descriptor length < 40");
  }

  switch(*packet_type)
  {
    /*
     * IP packet
     */
    case TYPE_IP:
      /*
       * if acknowledged mode
       */
      if(src_desc_list != dest_desc_list)
      {
        dest_desc_list->first = src_desc_list->first;
        dest_desc_list->list_len = src_desc_list->list_len;
      }
      TRACE_EVENT("INFO COMP: Header Type TYPE_IP");
      break;

    /*
     * Uncompressed TCP/IP packet
     */
    case TYPE_UNCOMPRESSED_TCP:
      /*
       * if acknowledged mode
       */
      if(src_desc_list != dest_desc_list)
      {
#ifdef _SNDCP_DTI_2_
      MALLOC(new_desc, (USHORT)(sizeof(T_desc2)-1+src_desc->len));
#else
      MALLOC(new_desc, (USHORT)(sizeof(T_desc)-1+src_desc->len));
#endif
        /*
         * Copy data packet to destination descriptor
         */
        memcpy(new_desc->buffer, src_desc_buff, src_desc->len);
        /*
         * store connection id
         */
        new_desc->buffer[PR_TYPE_POS] = ((UBYTE*)cbuf.c_hdr)[PR_TYPE_POS]
        ;/*lint !e644 !e415 !e416 creation and access of out-of-bounds pointer*/
        /*
         * Build destination descriptor list
         */
        new_desc->next   = src_desc->next;
        new_desc->len    = src_desc->len;
#ifdef _SNDCP_DTI_2_
        new_desc->offset = src_desc->offset;
        new_desc->size   = src_desc->size;
#endif
        dest_desc_list->first    = (ULONG)new_desc;
        dest_desc_list->list_len = src_desc_list->list_len;
      }
      else{
       /*
        * store connection id
        */
        src_desc_buff[PR_TYPE_POS] = ((UBYTE*)cbuf.c_hdr)[PR_TYPE_POS]
        ;/*lint !e415 !e416 creation and access of out-of-bounds pointer */
      }
      TRACE_EVENT("INFO COMP: Header Type TYPE_UNCOMPRESSED_TCP");
      break;


    /*
     * Compressed TCP/IP packet
     */
    case TYPE_COMPRESSED_TCP:
      /* compute compressed header length */
      offset = (USHORT)(src_desc->len - cbuf.pack_len);
#ifdef _SNDCP_DTI_2_
      MALLOC(new_desc, (USHORT)(sizeof(T_desc2) - 1 + cbuf.pack_len));
#else
      MALLOC(new_desc, (USHORT)(sizeof(T_desc) - 1 + cbuf.pack_len));
#endif
      /*
       * Copy compressed header to new descriptor
       */
      memcpy(&new_desc->buffer[0], (UBYTE*)cbuf.c_hdr, cbuf.hdr_len);
      /*
       * Copy payload to new descriptor
       */
      memcpy(&new_desc->buffer[cbuf.hdr_len],
             &src_desc_buff[hdr_len], cbuf.pack_len-cbuf.hdr_len)
       ;/*lint !e644 !e662 Possible creation of out-of-bounds pointer */
      /*
       * Build destination descriptor list
       */
      new_desc->next   = src_desc->next;
      new_desc->len    = (USHORT)cbuf.pack_len;
#ifdef _SNDCP_DTI_2_
      new_desc->offset = 0;
      new_desc->size   = (USHORT)cbuf.pack_len;
#endif
      dest_desc_list->first    = (ULONG)new_desc;
      dest_desc_list->list_len = src_desc_list->list_len - offset;
      /*
       * if unacknowledgement mode
       */
      if(src_desc_list == dest_desc_list)
      {
        /*
         * Free source decsriptor
         */
        MFREE(src_desc);
      }
      TRACE_EVENT("INFO COMP: Header TYPE_COMPRESSED_TCP");
      break;

    default:
      TRACE_EVENT("Header Type: TYPE_ERROR");
      break;
    }

#ifdef SNDCP_TRACE_BUFFER
    sndcp_trace_desc_list(dest_desc_list);
#endif /* SNDCP_TRACE_BUFFER */

} /* cia_header_comp*/

#endif /* CF_FAST_EXEC */


#ifndef _SNDCP_DTI_2_
/*
+------------------------------------------------------------------------------
| Function    : cia_su_cia_comp_req
+------------------------------------------------------------------------------
| Description : Simulation for cia reaction to SIG_SU_CIA_DATA_REQ.
|               Instead of sending the pdu to cia and then receiving
|               1 or more CIA_COMP_IND.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
/*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \
   !defined(REL99)   || defined(SNDCP_2to1) */

LOCAL void cia_su_cia_comp_req (T_SN_UNITDATA_REQ* sn_unitdata_req,
                                USHORT npdu_number,
                                UBYTE nsapi,
                                UBYTE sapi,
                                UBYTE packet_type
                                )
{
  BOOL ready = FALSE;
  USHORT header_size = SN_UNITDATA_PDP_HDR_LEN_BIG;
  /*
   * Bit offset in destination sdu.
   */
  USHORT bit_offset = ENCODE_OFFSET + (USHORT)(header_size << 3);
  /*
   * Offset in current desc.
   */
  USHORT desc_offset = 0;
  USHORT sdu_len = 0;
  UBYTE first = SEG_POS_FIRST;
  UBYTE segment_number = 0;
  T_desc_list* desc_list = &sn_unitdata_req->desc_list;

  TRACE_FUNCTION( "cia_su_cia_comp_req" );

  while (!ready && desc_list->first != NULL) {
   /*
    * How long will sdu be?
    */
    if (desc_list->list_len + header_size >= sndcp_data->su->n201_u) {
      sdu_len = (USHORT)(sndcp_data->su->n201_u << 3);
    } else {
      sdu_len = (USHORT)((desc_list->list_len + header_size) << 3);
    }
    {
      PALLOC_SDU(cia_comp_ind, CCI_COMP_IND, sdu_len);
      /*
       * Set parameters.
       */

      cia_comp_ind->sapi = sapi;
      /*
       * cia_qos is not yet used, set to 0.
       */
      cia_comp_ind->cia_qos.delay = 0;
      cia_comp_ind->cia_qos.relclass = 0;
      cia_comp_ind->cia_qos.peak = 0;
      cia_comp_ind->cia_qos.preced = 0;
      cia_comp_ind->cia_qos.mean = 0;
      /*
       * Will be changed as soon as more that 1 instance of V42.bis is used.
       */
      cia_comp_ind->algo_type = CIA_ALGO_V42;
      cia_comp_ind->comp_inst = CIA_COMP_INST_V42_0;

      cia_comp_ind->pdu_ref.ref_nsapi = nsapi;
      cia_comp_ind->pdu_ref.ref_npdu_num = npdu_number;
      cia_comp_ind->pdu_ref.ref_seg_num = segment_number;
      segment_number ++;
      if (desc_list->list_len + header_size <= sndcp_data->su->n201_u) {
        cia_comp_ind->seg_pos = first + SEG_POS_LAST;
      } else {
        cia_comp_ind->seg_pos = first;
      }
      cia_comp_ind->packet_type = packet_type;
      /*
       * Copy descriptors to cia_comp_ind->sdu.
       */
      while (desc_list->first != NULL) {
        T_desc* help = (T_desc*)desc_list->first;
        USHORT cur_len = (((T_desc*)desc_list->first)->len - desc_offset);
        if ((cur_len << 3) <=
             cia_comp_ind->sdu.l_buf +
             cia_comp_ind->sdu.o_buf -
             bit_offset) {

          /*
           * Copy current desc to sdu.
           */
          if (cur_len>0)
          {
            memcpy(&cia_comp_ind->sdu.buf[bit_offset >> 3],
                   &((T_desc*)desc_list->first)->buffer[desc_offset],
                   cur_len);
          }
          bit_offset += (USHORT)(cur_len << 3);
          desc_list->list_len -= cur_len;

          /*
           * Free read desc and go to next in list.
           */
          desc_list->first = help->next;
          desc_offset = 0;
          MFREE(help);
          help = NULL;
        } else {
          /*
           * Current desc does not fit completely in sdu.
           */
          USHORT part_len = (USHORT)(cia_comp_ind->sdu.l_buf +
                                    cia_comp_ind->sdu.o_buf -
                                    bit_offset)
                            >> 3;
          if (part_len > 0)
          {
            memcpy(&cia_comp_ind->sdu.buf[bit_offset >> 3],
                   &((T_desc*)desc_list->first)->buffer[desc_offset],
                   part_len);
            desc_offset += part_len;
          }
          desc_list->list_len -= part_len;

          header_size = SN_UNITDATA_PDP_HDR_LEN_SMALL;
          bit_offset = ENCODE_OFFSET + (USHORT)(header_size << 3);

          break;
        }
      } /* while (desc_list->first != NULL) { */
      /*
       * Instead of PSEND(SNDCP_handle, cia_comp_ind);
       */
      cia_cia_comp_ind(cia_comp_ind);
      /*
       * One segment sent, set 'first' to 'none'.
       */
      first = SEG_POS_NONE;
    }
    /*
     * If the desc_list is empty now, leave.
     */

    if (sn_unitdata_req->desc_list.list_len == 0) {
      PFREE(sn_unitdata_req);
      sn_unitdata_req = NULL;
      ready = TRUE;
    }
  }

} /* cia_su_cia_comp_req() */
/*#endif */ /* CF_FAST_EXEC || _SIMULATION_ || !REL99 || SNDCP_2to1 */

#else /* _SNDCP_DTI_2_ */
/*
+------------------------------------------------------------------------------
| Function    : cia_su_cia_comp_req
+------------------------------------------------------------------------------
| Description : This function is used, if no data compression is used in
|               uplink. It does only the segmentation of the incoming data.
| 
|               Simulation for cia reaction to SIG_SU_CIA_DATA_REQ.
|               Instead of sending the pdu to cia and then receiving
|               1 or more CIA_COMP_IND.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
/*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \
   !defined(REL99)   || defined(SNDCP_2to1) */

LOCAL void cia_su_cia_comp_req (T_SN_UNITDATA_REQ* sn_unitdata_req,
                                USHORT npdu_number,
                                UBYTE nsapi,
                                UBYTE sapi,
                                UBYTE packet_type
                                )
{
  BOOL ready = FALSE;
  U16 header_size = SN_UNITDATA_PDP_HDR_LEN_BIG;
  U16 desc2_data_struct_offset = 0;
  U8 first = SEG_POS_FIRST;
  U8 segment_number = 0;
  U32* segment_header;
  T_desc_list2* desc_list2 = &sn_unitdata_req->desc_list2;
  T_desc_list3 desc_list3;
  T_desc3* desc3;
  T_desc3* current_desc3;
  /*
   * Offset in current desc. Set the desc_offset to the offset of 
   * the first desc in the list that is to be read.
   */
  U16 desc_offset = ((T_desc2*)desc_list2->first)->offset;

  TRACE_FUNCTION( "cia_su_cia_comp_req" );

  while (!ready && desc_list2->first != NULL)
  {
   /*
    * How long will the segment be?
    */
    desc_list3.first = NULL;
    desc_list3.list_len = 0;
    if ((desc_list2->list_len + header_size) >= sndcp_data->su->n201_u)
    {
      desc_list3.list_len = (USHORT)sndcp_data->su->n201_u;
    }
    else
    {
      desc_list3.list_len = (USHORT)(desc_list2->list_len + header_size);
    }

    {
      T_CIA_COMP_IND *cia_comp_ind;
      MALLOC(cia_comp_ind, sizeof(T_CIA_COMP_IND));
      /*
       * Set parameters.
       */

      cia_comp_ind->sapi = sapi;
      /*
       * cia_qos is not yet used, set to 0.
       */
      cia_comp_ind->cia_qos.delay = 0;
      cia_comp_ind->cia_qos.relclass = 0;
      cia_comp_ind->cia_qos.peak = 0;
      cia_comp_ind->cia_qos.preced = 0;
      cia_comp_ind->cia_qos.mean = 0;
      /*
       * Will be changed as soon as more that 1 instance of V42.bis is used.
       */
      cia_comp_ind->algo_type = CIA_ALGO_V42;
      cia_comp_ind->comp_inst = CIA_COMP_INST_V42_0;

      cia_comp_ind->pdu_ref.ref_nsapi = nsapi;
      cia_comp_ind->pdu_ref.ref_npdu_num = npdu_number;
      cia_comp_ind->pdu_ref.ref_seg_num = segment_number;
      segment_number ++;

      /* Allocate memory for SNDCP header and LLC encode offset */
      MALLOC (segment_header, (USHORT)(ENCODE_OFFSET_BYTE + header_size));

      MALLOC (desc3, (U16)(sizeof(T_desc3)));
      /*
       * Fill desc3 descriptor control information.
       */
      desc3->next  = (U32)NULL;
      desc3->len   = header_size;
      desc3->offset = ENCODE_OFFSET_BYTE;
      desc3->buffer = (U32)segment_header;
      desc_list3.first = (U32)desc3;
      current_desc3 = desc3;

      if (desc_list2->list_len + header_size <= sndcp_data->su->n201_u)
      {
        cia_comp_ind->seg_pos = first + SEG_POS_LAST;
      } else {
        cia_comp_ind->seg_pos = first;
      }
      cia_comp_ind->packet_type = packet_type;
      cia_comp_ind->desc_list3.first = desc_list3.first;
      cia_comp_ind->desc_list3.list_len = desc_list3.list_len;

      desc_list3.list_len = 0;
      desc_list3.list_len += desc3->len;
      /*
       * Copy descriptors to cia_comp_ind->desc_list3, list may have to be built.
       */
      while (desc_list2->first != NULL)
      {/* This while moves data from desc2 to segment defined by desc3 descriptors*/
        T_desc2* help = (T_desc2*)desc_list2->first;
        U16 cur_len = (((T_desc2*)desc_list2->first)->len - desc_offset);
        desc2_data_struct_offset = offsetof(T_desc2, buffer);
        if (cur_len <= (sndcp_data->su->n201_u - desc_list3.list_len))
        {/* Is there room for all the desc2 data in the current segment */

          /*
           * describe current desc2 by desc3 descriptors.
           */

          MALLOC (desc3, (USHORT)(sizeof(T_desc3)));
          /*
           * Fill desc3 descriptor control information.
           */
          desc3->next  = (U32)NULL;
          desc3->len   = cur_len;
          desc3->offset = desc_offset + desc2_data_struct_offset;
          desc3->buffer = (U32)desc_list2->first;
          current_desc3->next = (U32)desc3;
          current_desc3 = desc3;
          desc_list3.list_len += desc3->len;

          /* Attach desc3 to desc2 allocation, this is always the last
             attach on a desc2 descriptor */
          sndcp_cl_desc2_attach(help);

          desc_list2->list_len -= cur_len;

          /*
           * Free read desc and go to next in list.
           */
          desc_list2->first = help->next;
          /* 
           * If another desc is present in the list to be read, then 
           * set the desc_offset to the offset of the next desc in the 
           * list that is to be read. Else set desc_offset to zero
           */
          if (desc_list2->first != NULL)
          {
            desc_offset = ((T_desc2*)desc_list2->first)->offset;
          }
          else
          {
            desc_offset = 0;
          }
          MFREE(help);
          help = NULL;
        } else {
          /*
           * Current desc does not fit completely in sdu.
           */

          USHORT part_len = (USHORT)(sndcp_data->su->n201_u - desc_list3.list_len);

          if (part_len > 0)
          {
            MALLOC (desc3, (USHORT)(sizeof(T_desc3)));
            /*
             * Fill desc3 descriptor control information.
             */
            desc3->next  = (ULONG)NULL;
            desc3->len   = part_len;
            desc3->offset = desc_offset + desc2_data_struct_offset;
            desc3->buffer = (ULONG)desc_list2->first;
            current_desc3->next = (ULONG)desc3;
            current_desc3 = desc3;
            desc_list3.list_len += desc3->len;

            /* Attach desc3 to desc2 allocation, this is an intermediate
               attach on a desc2 descriptor */
            sndcp_cl_desc2_attach(help);

            desc_offset += part_len;
          }
          desc_list2->list_len -= part_len;

          header_size = SN_UNITDATA_PDP_HDR_LEN_SMALL;
          break;
        }
      } /* while (desc_list->first != NULL) { */

      /*
       * Instead of PSEND(SNDCP_handle, cia_comp_ind);
       */
      cia_cia_comp_ind(cia_comp_ind);
      /*
       * One segment sent, set 'first' to 'none'.
       */
      first = SEG_POS_NONE;
    }
    /*
     * If the desc_list is empty now, leave.
     */
    if (sn_unitdata_req->desc_list2.list_len == 0) {

      MFREE(sn_unitdata_req);
      sn_unitdata_req = NULL;
      ready = TRUE;
    }
  }
} /* cia_su_cia_comp_req() */
/*#endif */ /* CF_FAST_EXEC || _SIMULATION_ || !REL99 || SNDCP_2to1 */

#ifdef TI_PS_FF_V42BIS
/*
+------------------------------------------------------------------------------
| Function    : cia_su_cci_comp_req
+------------------------------------------------------------------------------
| Description : This function is used, if data compression is used in uplink
|               direction. At first it calls the data compression function with
|               parameters, that allow a segmentation without memcopy. Than it
|               does the segmentation.
|
|               Simulation for CCI reaction to SIG_SU_CIA_DATA_REQ.
|               Instead of sending the pdu to CCI and then receiving
|               1 or more CCI_COMP_IND.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
/*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \
   !defined(REL99)   || defined(SNDCP_2to1) */
   
LOCAL void cia_su_cci_comp_req (T_SN_UNITDATA_REQ* sn_unitdata_req,
                                          USHORT npdu_number,
                                          UBYTE nsapi,
                                          UBYTE sapi,
                                          UBYTE packet_type
                                        )
{
  BOOL ready = FALSE;
  U16 header_size = SN_UNITDATA_PDP_HDR_LEN_BIG;
  U16 desc2_data_struct_offset = offsetof(T_desc2, buffer);
  U8 segment_position = SEG_POS_FIRST;
  U8 segment_number = 0;
  U32* segment_header;
  T_desc_list2* desc_list2 = &sn_unitdata_req->desc_list2;
  T_desc2* desc2;
  T_desc_list3 desc_list3;
  T_desc3* desc3;
  T_desc3* current_desc3;
  
  U8 descs_per_seg = 5;
  U8 i;
  U16 desc_size = (sndcp_data->su->n201_u - header_size -
                  (desc2_data_struct_offset + 1) * descs_per_seg) /
                  descs_per_seg +
                  desc2_data_struct_offset + 1;
  
  
  
  
  
  
  TRACE_FUNCTION( "cia_su_cci_comp_req" );
  TRACE_EVENT_P1("sn_unitdata_req in: %08x", sn_unitdata_req);
  //TRACE_EVENT_P1("PacketType: %d",packet_type);

  /*
   * Reset V.42 context and call the encoder routine
   */
  //TRACE_EVENT_P1("V42 ENC: Input Uncompressed Packet, length %d", desc_list2->list_len);
#ifdef SNDCP_TRACE_BUFFER
  //sndcp_trace_desc_list(desc_list2);
#endif
  v42b_init(sndcp_data->cia.enc, 0, 0, 0, 0);
  TRACE_FUNCTION ("as reinit in uplink");
  /*
   * the function can be called with 0s as parameters, because it was initialized
   * befor what the function sees on the valid magic number
   *
   * the call replaces an independent reinit function
   */
  v42b_encoder(sndcp_data->cia.enc, desc_list2, NULL, desc_size);
  //TRACE_EVENT_P1("V42 ENC: Output Compresset Packet, length %d", desc_list2->list_len);
#ifdef SNDCP_TRACE_BUFFER
  //sndcp_trace_desc_list(desc_list2);
#endif


  desc2 = (T_desc2*)desc_list2->first;

  while (desc2)
  {
    
    
    
    desc_list3.first = (U32) NULL;
    desc_list3.list_len = 0;
    

    MALLOC(segment_header, (ENCODE_OFFSET_BYTE + header_size));
    MALLOC(desc3,sizeof(T_desc3));

    desc3->next = (U32) NULL;
    desc3->len = header_size;
    desc3->offset = ENCODE_OFFSET_BYTE;
    desc3->buffer = (U32)segment_header;

    desc_list3.first = (U32)desc3;
    desc_list3.list_len = desc3->len;

    current_desc3 = desc3;

    for (i = 0; (i < descs_per_seg) && desc2; i++)
    {
      MALLOC(desc3,sizeof(T_desc3));

      desc3->next = (U32) NULL;
      desc3->len = desc2->len;
      desc3->offset = desc2->offset + desc2_data_struct_offset;
      desc3->buffer = (U32)desc2;

      current_desc3->next = (U32) desc3;
      current_desc3 = desc3;
      desc_list3.list_len += desc3->len;

      desc2 = (T_desc2*) desc2->next;
    }
    header_size = SN_UNITDATA_PDP_HDR_LEN_SMALL;

    {
      T_CIA_COMP_IND *cia_comp_ind;
      MALLOC(cia_comp_ind, sizeof(T_CIA_COMP_IND));
      /*
       * Set parameters.
       */

      cia_comp_ind->sapi = sapi;
      /*
       * cci_qos is not yet used, set to 0.
       */
      cia_comp_ind->cia_qos.delay = 0;
      cia_comp_ind->cia_qos.relclass = 0;
      cia_comp_ind->cia_qos.peak = 0;
      cia_comp_ind->cia_qos.preced = 0;
      cia_comp_ind->cia_qos.mean = 0;
      /*
       * Will be changed as soon as more that 1 instance of V42.bis is used.
       */
      cia_comp_ind->algo_type = CCI_ALGO_V42;
      cia_comp_ind->comp_inst = CCI_COMP_INST_V42_0;

      cia_comp_ind->pdu_ref.ref_nsapi = nsapi;
      cia_comp_ind->pdu_ref.ref_npdu_num = npdu_number;
      cia_comp_ind->pdu_ref.ref_seg_num = segment_number;
      segment_number ++;

      if (desc2 != NULL)
      {
        cia_comp_ind->seg_pos = segment_position;
      }
      else
      {
        cia_comp_ind->seg_pos = segment_position | SEG_POS_LAST;
      }

      cia_comp_ind->packet_type = packet_type;
      cia_comp_ind->desc_list3.first = desc_list3.first;
      cia_comp_ind->desc_list3.list_len = desc_list3.list_len;

      /*
       * Instead of PSEND(SNDCP_handle, cci_comp_ind);
       */
      cia_cia_comp_ind(cia_comp_ind);
      /*
       * One segment sent, set 'first' to 'none'.
       */
      segment_position = SEG_POS_NONE;
    }
  }
  /*
   * If the desc_list2 is empty now, leave.
   */
  TRACE_EVENT_P1("sn_unitdata_req out: %08x", sn_unitdata_req);
  MFREE(sn_unitdata_req);
  sn_unitdata_req = NULL;
}
/*#endif */ /* FAST_EXEC */
#endif /* TI_PS_FF_V42BIS */
#endif /* _SNDCP_DTI_2_ */

#ifdef _SNDCP_DTI_2_
/*
+------------------------------------------------------------------------------
| Function    : cia_sua_cia_comp_req
+------------------------------------------------------------------------------
| Description : Simulation for cia reaction to SIG_SUA_CIA_DATA_REQ.
|               Instead of sending the pdu to cia and then receiving
|               1 or more CIA_COMP_IND.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

LOCAL void cia_sua_cia_comp_req (T_desc_list2 dest_desc_list,
                                 U8 npdu_number,
                                 U8 nsapi,
                                 U8 sapi,
                                 U8 packet_type
                                 )
{
  BOOL ready = FALSE;
  U16 header_size = SN_DATA_PDP_HDR_LEN_BIG;
  U16 desc2_data_struct_offset = 0;
  U8 first = SEG_POS_FIRST;
  U8 segment_number = 0;
  U32* segment_header;
  T_desc_list2* desc_list2 = &dest_desc_list;
  T_desc_list3 desc_list3;
  T_desc3* desc3;
  T_desc3* current_desc3;
  USHORT list_len = desc_list2->list_len;
  T_desc2* help = (T_desc2*)desc_list2->first;
  T_desc2* delhelp = NULL;

  /* 
   * Offset in current descriptor  Set the desc_offset to the offset of 
   * the first desc in the list that is to be read.
   */
  U16 desc_offset = help->offset;

  TRACE_FUNCTION( "cia_sua_cia_comp_req" );

  while (!ready && help != NULL) {
   /*
    * How long will the segment be?
    */
    desc_list3.first = NULL;
    desc_list3.list_len = 0;
    if ((list_len + header_size) >= sndcp_data->sua->n201_i)
    {
      desc_list3.list_len = (U16)sndcp_data->sua->n201_i;
    }
    else
    {
      desc_list3.list_len = (U16)(list_len + header_size);
    }

    {
      /*
       * First desc in list must be header!!!
       */
      BOOL first_part = TRUE;

      T_CIA_COMP_IND *cia_comp_ind;
      MALLOC(cia_comp_ind, sizeof(T_CIA_COMP_IND));
      /*
       * Set parameters.
       */
      cia_comp_ind->sapi = sapi;
      /*
       * cia_qos is not yet used, set to 0.
       */
      cia_comp_ind->cia_qos.delay = 0;
      cia_comp_ind->cia_qos.relclass = 0;
      cia_comp_ind->cia_qos.peak = 0;
      cia_comp_ind->cia_qos.preced = 0;
      cia_comp_ind->cia_qos.mean = 0;
      /*
       * Will be changed as soon as more that 1 instance of V42.bis is used.
       */
      cia_comp_ind->algo_type = CIA_ALGO_V42;
      cia_comp_ind->comp_inst = CIA_COMP_INST_V42_0;

      cia_comp_ind->pdu_ref.ref_nsapi = nsapi;
      cia_comp_ind->pdu_ref.ref_npdu_num = npdu_number;
      cia_comp_ind->pdu_ref.ref_seg_num = segment_number;
      segment_number ++;

      /* Allocate memory for SNDCP header and LLC encode offset */
      MALLOC (segment_header, (U16)(ENCODE_OFFSET_BYTE + header_size));

      MALLOC (desc3, (U16)(sizeof(T_desc3)));
      /*
       * Fill desc3 descriptor control information.
       */
      desc3->next  = (U32)NULL;
      desc3->len   = header_size;
      desc3->offset = ENCODE_OFFSET_BYTE;
      desc3->buffer = (U32)segment_header;
      desc_list3.first = (U32)desc3;
      current_desc3 = desc3;

      if (list_len + header_size <= sndcp_data->sua->n201_i)
      {
        cia_comp_ind->seg_pos = first + SEG_POS_LAST;
      } else {
        cia_comp_ind->seg_pos = first;
      }
      cia_comp_ind->packet_type = packet_type;
      cia_comp_ind->desc_list3.first = desc_list3.first;
      cia_comp_ind->desc_list3.list_len = desc_list3.list_len;

      desc_list3.list_len = 0;
      desc_list3.list_len += desc3->len;
      /*
       * Copy descriptors to cia_comp_ind->desc_list3, list may have to be built.
       */
      while (help != NULL)
      {/*
        * This while moves data from desc2 to segment defined
        * by desc3 descriptors
        */
        U16 cur_len = (help->len - desc_offset);
        desc2_data_struct_offset = offsetof(T_desc2, buffer);
        if (cur_len <= (sndcp_data->sua->n201_i - desc_list3.list_len))
        {/* Is there room for all the desc2 data in the current segment */
          /*
           * describe current desc2 by desc3 descriptors.
           */
          if (cur_len>0)
          {
            MALLOC (desc3, (U16)(sizeof(T_desc3)));
            /*
             * Fill desc3 descriptor control information.
             */
            desc3->next  = (U32)NULL;
            desc3->len   = cur_len;
            desc3->offset = desc_offset + desc2_data_struct_offset;
            desc3->buffer = (U32)help;
            current_desc3->next = (ULONG)desc3;
            current_desc3 = desc3;
            desc_list3.list_len += desc3->len;

            /* Attach desc3 to desc2 allocation, this is always the last
               attach on a desc2 descriptor */
            sndcp_cl_desc2_attach(help);

          }
          list_len -= cur_len;

          /*
           * Free read desc and go to next in list.
           */
          if (help != NULL)
          {
            delhelp = help;
            help = (T_desc2*)help->next;
          }
          /* 
           * If another desc is present in the list to be read, then 
           * set the desc_offset to the offset of the next desc in the 
           * list that is to be read. Else set desc_offset to zero
           */
          if (help != NULL)
          {
            desc_offset = help->offset;
          }
          else
          {
            desc_offset = 0;
          }
          if (delhelp != NULL &&
              first_part &&
              (packet_type == TYPE_COMPRESSED_TCP ||
               packet_type == TYPE_UNCOMPRESSED_TCP)) {

            MFREE(delhelp);
            delhelp = NULL;
            first_part = FALSE;
          }
        }
        else
        {
          /*
           * Current desc does not fit completely in sdu.
           */

          U16 part_len = (USHORT)(sndcp_data->sua->n201_i-desc_list3.list_len);

          if (part_len>0)
          {
            MALLOC (desc3, (USHORT)(sizeof(T_desc3)));
            /*
             * Fill desc3 descriptor control information.
             */
            desc3->next  = (ULONG)NULL;
            desc3->len   = part_len;
            desc3->offset = desc_offset + desc2_data_struct_offset;
            desc3->buffer = (ULONG)help;
            current_desc3->next = (ULONG)desc3;
            current_desc3 = desc3;
            desc_list3.list_len += desc3->len;

            /* Attach desc3 to desc2 allocation, this is an intermediate
               attach on a desc2 descriptor */
            sndcp_cl_desc2_attach(help);

            desc_offset += part_len;
          }
          list_len -= part_len;

          header_size = SN_DATA_PDP_HDR_LEN_SMALL;
          break;
        }
      }
      /*
       * Instead of PSEND(SNDCP_handle, cia_comp_ind);
       */
      cia_cia_comp_ind(cia_comp_ind);
      /*
       * One segment sent, set 'first' to 'none'.
       */
      first = SEG_POS_NONE;
    }
    /*
     * If the desc_list is empty now, leave.
     */
    if (list_len == 0) {
      ready = TRUE;
    }
  }
} /* cia_sua_cia_comp_req() */

#endif /* CF_FAST_EXEC */

#else /* _SNDCP_DTI_2_ */
/*
+------------------------------------------------------------------------------
| Function    : cia_sua_cia_comp_req
+------------------------------------------------------------------------------
| Description : Simulation for cia reaction to SIG_SUA_CIA_DATA_REQ.
|               Instead of sending the pdu to cia and then receiving
|               1 or more CIA_COMP_IND.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

LOCAL void cia_sua_cia_comp_req (T_desc_list dest_desc_list,
                                 UBYTE npdu_number,
                                 UBYTE nsapi,
                                 UBYTE sapi,
                                 UBYTE packet_type
                                 )
{
  BOOL ready = FALSE;
  USHORT header_size = SN_DATA_PDP_HDR_LEN_BIG;
  USHORT bit_offset = ENCODE_OFFSET + (USHORT)(header_size << 3);
  USHORT desc_offset = 0;
  USHORT sdu_len = 0;
  UBYTE first = SEG_POS_FIRST;
  UBYTE segment_number = 0;
  T_desc_list* desc_list = &dest_desc_list;
  USHORT list_len = desc_list->list_len;
  T_desc* help = (T_desc*)desc_list->first;
  T_desc* delhelp = NULL;

  USHORT help_buffer_offset = 0;

  TRACE_FUNCTION( "cia_sua_cia_comp_req" );

  while (!ready && help != NULL) {
   /*
    * How long will sdu be?
    */
    if (list_len + header_size >= sndcp_data->sua->n201_i) {
      sdu_len = (USHORT)(sndcp_data->sua->n201_i << 3);
    } else {
      sdu_len = (USHORT)((list_len + header_size) << 3);
    }
    {
      /*
       * First desc in list must be header!!!
       */
      BOOL first_part = TRUE;

      PALLOC_SDU(cia_comp_ind, CCI_COMP_IND, sdu_len);   
      /*
       * Set parameters.
       */
      cia_comp_ind->sapi = sapi;
      /*
       * cia_qos is not yet used, set to 0.
       */
      cia_comp_ind->cia_qos.delay = 0;
      cia_comp_ind->cia_qos.relclass = 0;
      cia_comp_ind->cia_qos.peak = 0;
      cia_comp_ind->cia_qos.preced = 0;
      cia_comp_ind->cia_qos.mean = 0;
      /*
       * Will be changed as soon as more that 1 instance of V42.bis is used.
       */
      cia_comp_ind->algo_type = CIA_ALGO_V42;
      cia_comp_ind->comp_inst = CIA_COMP_INST_V42_0;

      cia_comp_ind->pdu_ref.ref_nsapi = nsapi;
      cia_comp_ind->pdu_ref.ref_npdu_num = npdu_number;
      cia_comp_ind->pdu_ref.ref_seg_num = segment_number;
      segment_number ++;
      if (list_len + header_size <= sndcp_data->sua->n201_i) {
        cia_comp_ind->seg_pos = first + SEG_POS_LAST;
      } else {
        cia_comp_ind->seg_pos = first;
      }
      cia_comp_ind->packet_type = packet_type;
      /*
       * Copy descriptors to cia_comp_ind->sdu.
       */
      while (help != NULL) {
        USHORT cur_len = (help->len - desc_offset);

        if ((cur_len << 3) <=
             cia_comp_ind->sdu.l_buf +
             cia_comp_ind->sdu.o_buf -
             bit_offset) {

          /*
           * Copy current desc to sdu.
           */
          if (cur_len>0)
          {
            memcpy(&cia_comp_ind->sdu.buf[bit_offset >> 3],
                   &help->buffer[desc_offset],
                   cur_len);
          }
          bit_offset += (USHORT)(cur_len << 3);
          list_len -= cur_len;

          /*
           * Free read desc and go to next in list.
           */
          if (help != NULL) {
            delhelp = help;
            help = (T_desc*)help->next;
          }
          help_buffer_offset = 0;
          desc_offset = 0;
          if (delhelp != NULL &&
              first_part &&
              (packet_type == TYPE_COMPRESSED_TCP ||
               packet_type == TYPE_UNCOMPRESSED_TCP)) {

            MFREE(delhelp);
            delhelp = NULL;
            first_part = FALSE;
          }
        } else {
          /*
           * Current desc does not fit completely in sdu.
           */
          desc_offset = (USHORT)(cia_comp_ind->sdu.l_buf +
                                 cia_comp_ind->sdu.o_buf -
                                 bit_offset)
                         >> 3;
          if (desc_offset>0)
          {
            memcpy(&cia_comp_ind->sdu.buf[bit_offset >> 3],
                   &help->buffer[help_buffer_offset],
                   desc_offset);
            help_buffer_offset += (desc_offset);
          }
          list_len -= desc_offset;

          header_size = SN_DATA_PDP_HDR_LEN_SMALL;
          bit_offset = ENCODE_OFFSET + (USHORT)(header_size << 3);
          break;
        }
      }
      /*
       * Instead of PSEND(SNDCP_handle, cia_comp_ind);
       */
      cia_cia_comp_ind(cia_comp_ind);
      /*
       * One segment sent, set 'first' to 'none'.
       */
      first = SEG_POS_NONE;
    }
    /*
     * If the desc_list is empty now, leave.
     */
    if (list_len == 0) {
      ready = TRUE;
    }
  }

} /* cia_sua_cia_comp_req() */

#endif /* CF_FAST_EXEC */

#endif /*_SNDCP_DTI_2_*/


/*
+------------------------------------------------------------------------------
| Function    : cia_sd_cia_decomp_req
+------------------------------------------------------------------------------
| Description : This Function does the defragmentation for noncompressed data.
| 
| Simulation for cia reaction to SIG_SD_CIA_TRANSFER_REQ.
| If (cur_seg_pos & SEG_POS_FIRST > 0) then a new CIA_DECOMP_IND is allocated.
| T_desc is allocated with the length of the sdu included in the
| ll_unitdata_ind. The sdu data is copied to the desc and the desc is added to
| the currently assembled desc_list in the current CIA_DECOMP_IND.
| If (cur_seg_pos & SEG_POS_LAST > 0) then a the CIA_DECOMP_IND is now complete
| and is "sent to this service" by calling the cia function cia_cia_decomp_ind.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
/*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \
   !defined(REL99)   || defined(SNDCP_2to1) */

GLOBAL void cia_sd_cia_decomp_req(T_LL_UNITDATA_IND* ll_unitdata_ind)
{
  USHORT length = 0;
  USHORT header_len = SN_UNITDATA_PDP_HDR_LEN_SMALL;
  USHORT sdu_index = 0;
  T_CIA_DECOMP_IND *cur_cia_decomp_ind;
  UBYTE nsapi;
#ifdef _SNDCP_DTI_2_
  T_desc2* help = NULL;
  T_desc2* descriptor = NULL;
#else /*_SNDCP_DTI_2_*/
  T_desc* help = NULL;
  T_desc* descriptor = NULL;
#endif /*_SNDCP_DTI_2_*/

  TRACE_FUNCTION( "cia_sd_cia_decomp_req" );

  nsapi = (ll_unitdata_ind->sdu.buf[(ll_unitdata_ind->sdu.o_buf / 8)]) & 0xf;
  cur_cia_decomp_ind = sndcp_data->cia.cur_cia_decomp_ind[nsapi];
  
  /*
   * In case of first segment allocate new N-PDU.
   */
  if ((sndcp_data->cur_seg_pos[nsapi] & SEG_POS_FIRST) > 0) {
    {

      T_CIA_DECOMP_IND *cia_decomp_ind;
      MALLOC(cia_decomp_ind, sizeof(T_CIA_DECOMP_IND));

#ifdef SNDCP_TRACE_ALL

      sndcp_data->cia.cia_decomp_ind_number[nsapi] ++;
      TRACE_EVENT_P1("number of cia_decomp_ind: % d",
                     sndcp_data->cia.cia_decomp_ind_number[nsapi]);
#endif /* SNDCP_TRACE_ALL */


      /*
       * if there is an unfinished cur_cia_decomp_ind deallocate it together
       * with the allocated descriptors
       */
      if (cur_cia_decomp_ind NEQ NULL)
      {
        MFREE_PRIM(cur_cia_decomp_ind);
        TRACE_EVENT("Deallocate unfinished cur_cia_decomp_ind");
      }
      cur_cia_decomp_ind = cia_decomp_ind;
      /*
       * Will be changed as soon as more that 1 instance of V42.bis is used.
       */
      cur_cia_decomp_ind->algo_type = CIA_ALGO_V42;
      cur_cia_decomp_ind->comp_inst = CIA_COMP_INST_V42_0;

      cur_cia_decomp_ind->pdu_ref = sndcp_data->cur_pdu_ref[nsapi];
      cur_cia_decomp_ind->desc_list2.first = (ULONG)NULL;
      cur_cia_decomp_ind->desc_list2.list_len = 0;

      header_len = SN_UNITDATA_PDP_HDR_LEN_BIG;
      cia_decomp_ind->pcomp =
        ll_unitdata_ind->sdu.buf[(ll_unitdata_ind->sdu.o_buf >> 3) + 1] & 0xf;
    }
  }
  /*
   * If big header has been received in state != RECEIVE_FIRST_SEGMENT
   */
  if (sndcp_data->big_head[nsapi]) {
    header_len = SN_UNITDATA_PDP_HDR_LEN_BIG;
  }
  sdu_index = (ll_unitdata_ind->sdu.o_buf >> 3) + header_len;
  length = (ll_unitdata_ind->sdu.l_buf >> 3) - header_len;
  /*
   * Allocate new descriptor and copy sdu data.
   */
#ifdef _SNDCP_DTI_2_
  MALLOC (descriptor, (USHORT)(sizeof(T_desc2) - 1 + length));
#else /*_SNDCP_DTI_2_*/
  MALLOC (descriptor, (USHORT)(sizeof(T_desc) - 1 + length));
#endif /*_SNDCP_DTI_2_*/

  /*
   * Fill descriptor control information.
   */
  descriptor->next  = (ULONG)NULL;
  descriptor->len   = length;
#ifdef _SNDCP_DTI_2_
  descriptor->offset = 0;
  descriptor->size = descriptor->len;
#endif

  /*
   * Add length of descriptor data to list length.
   */
  cur_cia_decomp_ind->desc_list2.list_len += length;

  /*
   * Copy user data from SDU to descriptor.
   */
  if (length>0)
  {
    memcpy (descriptor->buffer,
            &ll_unitdata_ind->sdu.buf[sdu_index],
            length);
  }

  /*
   * Add desc to desc_list.
   */
#ifdef _SNDCP_DTI_2_
  help = (T_desc2*)cur_cia_decomp_ind->desc_list2.first;
#else /*_SNDCP_DTI_2_*/
  help = (T_desc*)cur_cia_decomp_ind->desc_list2.first;
#endif /*_SNDCP_DTI_2_*/
  if (help == NULL) {
    cur_cia_decomp_ind->desc_list2.first = (ULONG)descriptor;
  } else {
    if (help->next == NULL) {
      help->next = (ULONG) descriptor;
    } else {
      while (help->next != NULL) {
#ifdef _SNDCP_DTI_2_
        help = (T_desc2*)help->next;
#else /*_SNDCP_DTI_2_*/
        help = (T_desc*)help->next;
#endif /*_SNDCP_DTI_2_*/
      }
      help->next = (ULONG)descriptor;
    }
  }

  /*
   * If this is the last segment, send it to this same service with a simulated
   * primitive.
   */
  if ((sndcp_data->cur_seg_pos[nsapi] & SEG_POS_LAST) > 0) {
    /*
     * By now algo_type, cia_qos and comp_inst are not evaluated.
     */
    cur_cia_decomp_ind->pdu_ref = sndcp_data->cur_pdu_ref[nsapi];
    cia_cia_decomp_ind(cur_cia_decomp_ind);
    cur_cia_decomp_ind = NULL;
  } else {
    /*
     * Request next segment.
     */
    sd_get_unitdata_if_nec(ll_unitdata_ind->sapi);
  }
  /*
   * Update global current CIA_DECOMP_IND
   */
  sndcp_data->cia.cur_cia_decomp_ind[nsapi] = cur_cia_decomp_ind;
  /*
   * Free incoming prim.
   */
  if (ll_unitdata_ind != NULL) {
    PFREE (ll_unitdata_ind);
    ll_unitdata_ind = NULL;
  }
} /* cia_sd_cia_decomp_req() */

/*#endif */ /* CF_FAST_EXEC || _SIMULATION_ || !REL99 || SNDCP_2to1 */

#ifdef TI_PS_FF_V42BIS
/*
+------------------------------------------------------------------------------
| Function    : cia_sd_cci_decomp_req
+------------------------------------------------------------------------------
| Description : This function does the desegmentation and decomressoin for 
|               compressed data.
|
| Simulation for CCI reaction to SIG_SD_CIA_TRANSFER_REQ.
| If (cur_seg_pos & SEG_POS_FIRST > 0) then a new CCI_DECOMP_IND is allocated.
| T_desc is allocated with the length of the sdu included in the
| ll_unitdata_ind. The sdu data is copied to the desc and the desc is added to
| the currently assembled desc_list in the current CCI_DECOMP_IND.
| If (cur_seg_pos & SEG_POS_LAST > 0) then a the CCI_DECOMP_IND is now complete
| and is "sent to this service" by calling the cia function cia_cci_decomp_ind.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
/*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \
   !defined(REL99)   || defined(SNDCP_2to1) */

LOCAL void cia_sd_cci_decomp_req (/*T_pdu_ref pdu_ref,
                                  USHORT cur_seg_pos,
                                  */T_LL_UNITDATA_IND* ll_unitdata_ind
                                  )
{

  USHORT length = 0;
  USHORT header_len = SN_UNITDATA_PDP_HDR_LEN_SMALL;
  USHORT sdu_index = 0;
  T_CIA_DECOMP_IND *cur_cia_decomp_ind;
  UBYTE nsapi;
#ifdef _SNDCP_DTI_2_
  T_desc2* help = NULL;
  T_desc2* descriptor = NULL;
#else /*_SNDCP_DTI_2_*/
  T_desc* help = NULL;
  T_desc* descriptor = NULL;
#endif /*_SNDCP_DTI_2_*/

  TRACE_FUNCTION( "cia_sd_cci_decomp_req" );
  
  nsapi = (ll_unitdata_ind->sdu.buf[(ll_unitdata_ind->sdu.o_buf / 8)]) & 0xf;
  cur_cia_decomp_ind = sndcp_data->cia.cur_cia_decomp_ind[nsapi];
  
  /*
   * In case of first segment allocate new N-PDU.
   */
  if ((sndcp_data->cur_seg_pos[nsapi] & SEG_POS_FIRST) > 0) 
  {
    {
      T_CIA_DECOMP_IND *cia_decomp_ind;
      MALLOC(cia_decomp_ind, sizeof(T_CIA_DECOMP_IND));

#ifdef SNDCP_TRACE_ALL

      sndcp_data->cia.cia_decomp_ind_number[nsapi] ++;
      TRACE_EVENT_P1("number of cia_decomp_ind: % d",
                     sndcp_data->cia.cia_decomp_ind_number[nsapi]);
#endif /* SNDCP_TRACE_ALL */


      /*
       * if there is an unfinished cur_cia_decomp_ind deallocate it together
       * with the allocated descriptors
       */
      if (cur_cia_decomp_ind NEQ NULL)
      {
        MFREE_PRIM(cur_cia_decomp_ind);
        TRACE_EVENT("Deallocate unfinished cur_cia_decomp_ind");
      }
      cur_cia_decomp_ind = cia_decomp_ind;
      /*
       * Will be changed as soon as more that 1 instance of V42.bis is used.
       */
      cur_cia_decomp_ind->algo_type = CIA_ALGO_V42;
      cur_cia_decomp_ind->comp_inst = CIA_COMP_INST_V42_0;

      cur_cia_decomp_ind->pdu_ref = sndcp_data->cur_pdu_ref[nsapi];
      cur_cia_decomp_ind->desc_list2.first = (ULONG)NULL;
      cur_cia_decomp_ind->desc_list2.list_len = 0;

      header_len = SN_UNITDATA_PDP_HDR_LEN_BIG;
      cia_decomp_ind->pcomp =
        ll_unitdata_ind->sdu.buf[(ll_unitdata_ind->sdu.o_buf >> 3) + 1] & 0xf;
    }
  }
  /*
   * If big header has been received in state != RECEIVE_FIRST_SEGMENT
   */
  if (sndcp_data->big_head[nsapi]) {
    header_len = SN_UNITDATA_PDP_HDR_LEN_BIG;
  }
  sdu_index = (ll_unitdata_ind->sdu.o_buf >> 3) + header_len;
  length = (ll_unitdata_ind->sdu.l_buf >> 3) - header_len;
  /*
   * Allocate new descriptor and copy sdu data.
   */
#ifdef _SNDCP_DTI_2_
  MALLOC (descriptor, (USHORT)(sizeof(T_desc2) - 1 + length));
#else /*_SNDCP_DTI_2_*/
  MALLOC (descriptor, (USHORT)(sizeof(T_desc) - 1 + length));
#endif /*_SNDCP_DTI_2_*/

  /*
   * Fill descriptor control information.
   */
  descriptor->next  = (ULONG)NULL;
  descriptor->len   = length;
#ifdef _SNDCP_DTI_2_
  descriptor->offset = 0;
  descriptor->size = descriptor->len;
#endif

  /*
   * Add length of descriptor data to list length.
   */
  cur_cia_decomp_ind->desc_list2.list_len += length;

  /*
   * Copy user data from SDU to descriptor.
   */
  if (length>0)
  {
    memcpy (descriptor->buffer,
            &ll_unitdata_ind->sdu.buf[sdu_index],
            length);
  }

  /*
   * Add desc to desc_list.
   */
#ifdef _SNDCP_DTI_2_
  help = (T_desc2*)cur_cia_decomp_ind->desc_list2.first;
#else /*_SNDCP_DTI_2_*/
  help = (T_desc*)cur_cia_decomp_ind->desc_list2.first;
#endif /*_SNDCP_DTI_2_*/
  if (help == NULL) {
    cur_cia_decomp_ind->desc_list2.first = (ULONG)descriptor;
  } else {
    if (help->next == NULL) {
      help->next = (ULONG) descriptor;
    } else {
      while (help->next != NULL) {
#ifdef _SNDCP_DTI_2_
        help = (T_desc2*)help->next;
#else /*_SNDCP_DTI_2_*/
        help = (T_desc*)help->next;
#endif /*_SNDCP_DTI_2_*/
      }
      help->next = (ULONG)descriptor;
    }
  }

  /*
   * If this is the last segment, send it to this same service with a simulated
   * primitive.
   */
  if ((sndcp_data->cur_seg_pos[nsapi] & SEG_POS_LAST) > 0) 
  {
    T_desc_list2 desc_list2;
    /*
     * By now algo_type, cci_qos and comp_inst are not evaluated.
     */
    cur_cia_decomp_ind->pdu_ref = sndcp_data->cur_pdu_ref[nsapi];

    desc_list2.first = cur_cia_decomp_ind->desc_list2.first;
    desc_list2.list_len = cur_cia_decomp_ind->desc_list2.list_len;

    /*
     * Reset V.42 context and call the decoder routine.
     */
    TRACE_EVENT_P1("V42 DEC: Input Compresset Packet, length %d", desc_list2.list_len);
#ifdef SNDCP_TRACE_BUFFER
    sndcp_trace_desc_list(&desc_list2);

    sndcp_data->cia.trabu[0] = 0;///////////////////////////////////////////////////////////////

#endif
    v42b_init(sndcp_data->cia.dec, 0, 0, 0, 0);
    TRACE_EVENT ("as reinit in downlink");
    /*
     * the function can be called with 0s as parameters, because it was initialized
     * befor what the function sees on the valid magic number
     *
     * the call replaces an independent reinit function
     */
    v42b_decoder(sndcp_data->cia.dec, &desc_list2, NULL, 100);
    if (!IS_ERROR(sndcp_data->cia.dec))
    {
      TRACE_EVENT_P1("V42 DEC: Output Decompressed Packet, length %d", desc_list2.list_len);
#ifdef SNDCP_TRACE_BUFFER
      sndcp_trace_desc_list(&desc_list2);
#endif

      cur_cia_decomp_ind->desc_list2.first = desc_list2.first;
      cur_cia_decomp_ind->desc_list2.list_len = desc_list2.list_len;
      
      cia_cia_decomp_ind(cur_cia_decomp_ind);
      cur_cia_decomp_ind = NULL;
    } 
    else 
    {
      MFREE_PRIM (cur_cia_decomp_ind);
      cur_cia_decomp_ind = NULL;
      TRACE_EVENT("Deallocate corrupted V.42 bis packet");

      /*
       * Request next segment.
       */
      sd_get_unitdata_if_nec(ll_unitdata_ind->sapi);
    }
  } 
  else 
  {
    /*
     * Request next segment.
     */
    sd_get_unitdata_if_nec(ll_unitdata_ind->sapi);
  }
  /*
   * Update global current CIA_DECOMP_IND
   */
   sndcp_data->cia.cur_cia_decomp_ind[nsapi] = cur_cia_decomp_ind;
  /*
   * Free incoming prim.
   */
  if (ll_unitdata_ind != NULL) {
    PFREE (ll_unitdata_ind);
    ll_unitdata_ind = NULL;
  }
} /* cia_sd_cci_decomp_req_sim() */

/* #endif *//* CF_FAST_EXEC || _SIMULATION_ || !REL99 || SNDCP_2to1 */
#endif /* TI_PS_FF_V42BIS */

/*
+------------------------------------------------------------------------------
| Function    : sig_sda_cia_cia_decomp_req
+------------------------------------------------------------------------------
| Description : Simulation for cia reaction to SIG_SDA_CIA_TRANSFER_REQ.
| If (cur_seg_pos & SEG_POS_FIRST > 0) then a new CIA_DECOMP_IND is allocated.
| T_desc is allocated with the length of the sdu included in the
| ll_data_ind. The sdu data is copied to the desc and the desc is added to
| the currently assembled desc_list in the current CCI_DECOMP_IND.
| If (cur_seg_pos & SEG_POS_LAST > 0) then a the CIA_DECOMP_IND is now complete
| and is "sent to this service" by calling the cia function cia_cia_decomp_ind.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sig_sda_cia_cia_decomp_req ( T_LL_DATA_IND* ll_data_ind )
{
  USHORT length = 0;
  USHORT header_len = SN_DATA_PDP_HDR_LEN_SMALL;
  USHORT sdu_index = 0;
  T_CIA_DECOMP_IND *cur_cia_decomp_ind;
  UBYTE nsapi = 0;
#ifdef _SNDCP_DTI_2_
  T_desc2* help = NULL;
  T_desc2* local_desc = NULL;
#else /*_SNDCP_DTI_2_*/
  T_desc* help = NULL;
  T_desc* local_desc = NULL;
#endif /*_SNDCP_DTI_2_*/

  TRACE_FUNCTION( "cia_sig_sda_cia_cia_decomp_req_sim" );

  nsapi = (ll_data_ind->sdu.buf[(ll_data_ind->sdu.o_buf / 8)]) & 0xf;
  cur_cia_decomp_ind = sndcp_data->cia.cur_cia_decomp_ind[nsapi];

  /*
   * In case of first segment allocate new N-PDU.
   */
  if ((sndcp_data->cur_seg_pos[nsapi] & SEG_POS_FIRST) > 0) {

    T_CIA_DECOMP_IND *cia_decomp_ind;
    MALLOC(cia_decomp_ind, sizeof(T_CIA_DECOMP_IND));

#ifdef SNDCP_TRACE_ALL
    sndcp_data->cia.cia_decomp_ind_number[nsapi] ++;
    TRACE_EVENT_P1("number of cia_decomp_ind: % d",
                   sndcp_data->cia.cia_decomp_ind_number[nsapi]);
#endif

    if (cur_cia_decomp_ind NEQ NULL)
    {
      MFREE_PRIM(cur_cia_decomp_ind);
      TRACE_EVENT("Deallocate unfinished cur_cia_decomp_ind");
    }

    cur_cia_decomp_ind = cia_decomp_ind;

    /*
     * Will be changed as soon as more that 1 instance of V42.bis is used.
     */
    cur_cia_decomp_ind->algo_type = CIA_ALGO_V42;
    cur_cia_decomp_ind->comp_inst = CIA_COMP_INST_V42_0;

    cur_cia_decomp_ind->pdu_ref = sndcp_data->cur_pdu_ref[nsapi];
    cur_cia_decomp_ind->desc_list2.first = (ULONG)NULL;
    cur_cia_decomp_ind->desc_list2.list_len = 0;

    header_len = SN_DATA_PDP_HDR_LEN_BIG;
    cia_decomp_ind->pcomp =
      ll_data_ind->sdu.buf[(ll_data_ind->sdu.o_buf >> 3) + 1] & 0xf;

  }
  /*
   * If big header has been received in state != RECEIVE_FIRST_SEGMENT
   */
  if (sndcp_data->big_head[nsapi]) {
    header_len = SN_DATA_PDP_HDR_LEN_BIG;
  }
  sdu_index = (ll_data_ind->sdu.o_buf >> 3) + header_len;
  
  if ((ll_data_ind->sdu.l_buf >> 3) < header_len){
     /*This condition is added as part of fix for GCF 46.1.2.2.3.2 failure because of wrong length*/
     TRACE_ERROR("SNDCP: Unexpected Length of N-PDU");
     PFREE (ll_data_ind);
     ll_data_ind = NULL;
     return;
  }else{

     length = (ll_data_ind->sdu.l_buf >> 3) - header_len;
  }

  /*
   * Allocate new descriptor and copy sdu data.
   */
#ifdef _SNDCP_DTI_2_
  MALLOC (local_desc, (USHORT)(sizeof(T_desc2) - 1 + length));
#else /*_SNDCP_DTI_2_*/
  MALLOC (local_desc, (USHORT)(sizeof(T_desc) - 1 + length));
#endif /*_SNDCP_DTI_2_*/

  /*
   * Fill descriptor control information.
   */
  local_desc->next  = (ULONG)NULL;
  local_desc->len   = length;
#ifdef _SNDCP_DTI_2_
  local_desc->offset = 0;
  local_desc->size = local_desc->len;
#endif
  /*
   * Add length of descriptor data to list length.
   */
  cur_cia_decomp_ind->desc_list2.list_len += length;

  /*
   * Copy user data from SDU to descriptor.
   */
  if (length>0)
  {
    memcpy (local_desc->buffer, &ll_data_ind->sdu.buf[sdu_index], length);
  }

  /*
   * Add desc to desc_list.
   */
#ifdef _SNDCP_DTI_2_
  help = (T_desc2*)cur_cia_decomp_ind->desc_list2.first;
#else /*_SNDCP_DTI_2_*/
  help = (T_desc*)cur_cia_decomp_ind->desc_list2.first;
#endif /*_SNDCP_DTI_2_*/
  if (help == NULL) {
    cur_cia_decomp_ind->desc_list2.first = (ULONG)local_desc;
  } else {
    if (help->next == NULL) {
      help->next = (ULONG) local_desc;
    } else {
      while (help->next != NULL) {
#ifdef _SNDCP_DTI_2_
        help = (T_desc2*)help->next;
#else /*_SNDCP_DTI_2_*/
        help = (T_desc*)help->next;
#endif /*_SNDCP_DTI_2_*/
      }
      help->next = (ULONG)local_desc;
    }
  }
  /*
   * If this is the last segment, send it to this same service with a simulated
   * primitive.
   */
  if ((sndcp_data->cur_seg_pos[nsapi] & SEG_POS_LAST) > 0) {
    /*
     * By now algo_type and comp_inst are not evaluated.
     */
    cur_cia_decomp_ind->pdu_ref = sndcp_data->cur_pdu_ref[nsapi];
    cia_cia_decomp_ind(cur_cia_decomp_ind);
    cur_cia_decomp_ind = NULL;
    /*
     * Reset the Current Segment Counter to zero, since we have received the 
     * last segment 
     */
    sndcp_data->cur_segment_number[nsapi] = 0;
  } else {
    /*
     * Check the Current Segment Number whether we have received more than 
     * SNDCP_MAX_SEGMENT_NUMBER segments or not. If we have received more than 
     * SNDCP_MAX_SEGMENT_NUMBER segments in a single NPDU, then we will discard
     * the stored segments and also the remaining segments of this NPDU, till 
     * we receive that last segment of this NPDU.
     * This has been done in order to encounter the PARTITION problem which
     * we will face if we keep on storing the segments in SNDCP.
     */
    sndcp_data->cur_segment_number[nsapi] ++;
    if (sndcp_data-> cur_segment_number[nsapi] > SNDCP_MAX_SEGMENT_NUMBER)
    {
      TRACE_EVENT("Segment Number in Single NPDU exceeds max segment number");

      /* Deleting the stored segments */
      sig_mg_cia_delete_npdus(nsapi);

      /* Change the state to SDA_ACK_DISCARD */
      sndcp_set_nsapi_rec_state(nsapi, SDA_ACK_DISCARD);
    }

    /*
     * Request next segment.
     */
    sda_get_data_if_nec(ll_data_ind->sapi);
  }
  /*
   * Update global current CIA_DECOMP_IND
   */
  sndcp_data->cia.cur_cia_decomp_ind[nsapi] = cur_cia_decomp_ind;
  /*
   * Free incoming prim.
   */
  if (ll_data_ind != NULL) {
    PFREE (ll_data_ind);
    ll_data_ind = NULL;
  }
} /* cia_sig_sda_cia_cia_decomp_req_sim() */

#endif /* CF_FAST_EXEC */


/*==== PUBLIC FUNCTIONS =====================================================*/

/*
+------------------------------------------------------------------------------
| Function    : sig_mg_cia_reset_ind
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_MG_CIA_RESET_IND
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sig_mg_cia_reset_ind (void)
{
  TRACE_ISIG( "sig_mg_cia_reset_ind" );

  switch( GET_STATE(CIA) )
  {
    case CIA_DEFAULT:
      sndcp_reset_xid_block(&sndcp_data->cia.cur_xid_block);
      break;
    default:
      TRACE_ERROR( "SIG_MG_CIA_RESET_IND unexpected" );
      break;
  }
} /* sig_mg_cia_reset_ind() */

#endif /* CF_FAST_EXEC */


/*
+------------------------------------------------------------------------------
| Function    : sig_su_cia_cia_comp_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_SU_CIA_CIA_COMP_REQ
|               This function makes a decision whether we are using data
|               compression in uplink direction and calls the according
|               function.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
/*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \
   defined(SNDCP_2to1) */

GLOBAL void sig_su_cia_cia_comp_req (T_SN_UNITDATA_REQ* sn_unitdata_req,
                                 USHORT npdu_number,
                                 UBYTE nsapi,
                                 UBYTE sapi
                                 )
{
  U8 direction = 0;
  BOOL compressed = FALSE;
  UBYTE packet_type = TYPE_IP;
  TRACE_ISIG( "sig_su_cia_cia_comp_req" );

  switch( GET_STATE(CIA) )
  {
    case CIA_DEFAULT:
      sndcp_is_nsapi_header_compressed(nsapi, &compressed);
      if (compressed) {
#ifdef _SNDCP_DTI_2_
        cia_header_comp(&sn_unitdata_req->desc_list2,
                        &sn_unitdata_req->desc_list2,
                        &packet_type);
#else /*_SNDCP_DTI_2_*/
        cia_header_comp(&sn_unitdata_req->desc_list,
                        &sn_unitdata_req->desc_list,
                        &packet_type);
#endif /*_SNDCP_DTI_2_*/
      }

      sndcp_is_nsapi_data_compressed(nsapi, &compressed);
      if (sndcp_data->cia.cur_xid_block.v42.is_set)
      {
        if (sndcp_data->cia.cur_xid_block.v42.p0_set)
        {
          direction = sndcp_data->cia.cur_xid_block.v42.p0;
          TRACE_EVENT_P1("dir: %d",direction);
        }
      }
      if (compressed && (direction & 0x01)) { /* datacompr. in uplink ? */
#ifdef TI_PS_FF_V42BIS

        cia_su_cci_comp_req(sn_unitdata_req,
                            npdu_number,
                            nsapi,
                            sapi,
                            packet_type);

#else  /* !TI_PS_FF_V42BIS */
        TRACE_EVENT("INFO CIA: Data compression is not implemented yet!");
        MFREE_PRIM(sn_unitdata_req);
        sn_unitdata_req = NULL;

#endif /* TI_PS_FF_V42BIS */
      } else { /* if (compressed)  */
        cia_su_cia_comp_req(sn_unitdata_req,
                                    npdu_number,
                                    nsapi,
                                    sapi,
                                    packet_type);
      }
      break;
    default:
      TRACE_ERROR( "SIG_SU_CIA_CIA_COMP_REQ unexpected" );
#ifdef _SNDCP_DTI_2_
      MFREE_PRIM(sn_unitdata_req);
#else /*_SNDCP_DTI_2_*/
      PFREE_DESC(sn_unitdata_req);
#endif /*_SNDCP_DTI_2_*/
      break;
  }
} /* sig_su_cia_cia_comp_req() */

/*#endif */ /* CF_FAST_EXEC || _SIMULATION_ || !REL99 || SNDCP_2to1 */

/*
+------------------------------------------------------------------------------
| Function    : sig_sua_cia_cia_comp_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_SUA_CIA_CIA_COMP_REQ
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sig_sua_cia_cia_comp_req (T_SN_DATA_REQ* sn_data_req,
                                 UBYTE npdu_number,
                                 UBYTE nsapi,
                                 UBYTE sapi
                                 )
{
  BOOL compressed = FALSE;
  UBYTE packet_type = TYPE_IP;
  /*
   * define desc_list for comp header. Is initialized later.
   */
#ifdef _SNDCP_DTI_2_
  T_desc_list2 dest_desc_list;
#else /*_SNDCP_DTI_2_*/
  T_desc_list dest_desc_list;
#endif /*_SNDCP_DTI_2_*/

  TRACE_ISIG( "sig_sua_cia_cia_comp_req" );

  switch( GET_STATE(CIA) )
  {
    case CIA_DEFAULT:
      sndcp_is_nsapi_header_compressed(nsapi, &compressed);
      if (compressed) {
#ifdef _SNDCP_DTI_2_
        cia_header_comp(&dest_desc_list,
                        &sn_data_req->desc_list2,
                        &packet_type);
      } else {
        dest_desc_list = sn_data_req->desc_list2;
#else /*_SNDCP_DTI_2_*/
        cia_header_comp(&dest_desc_list,
                        &sn_data_req->desc_list,
                        &packet_type);
      } else {
        dest_desc_list = sn_data_req->desc_list;
#endif /*_SNDCP_DTI_2_*/
      }

      sndcp_is_nsapi_data_compressed(nsapi, &compressed);
      if (compressed) {

       /*
        * The data compression routine shall be invoked here.
        */
        TRACE_EVENT("INFO CIA: Data compression is not implemented yet!");
        MFREE_PRIM(sn_data_req);
        sn_data_req = NULL;

      } else { /* if (compressed) */
        cia_sua_cia_comp_req(dest_desc_list,
                                     npdu_number,
                                     nsapi,
                                     sapi,
                                     packet_type);
      }
      /*
       * free comp header
       */
      if (compressed && dest_desc_list.first != 0) {
        MFREE(dest_desc_list.first);
        dest_desc_list.first = 0;
      }
      break;
    default:
      TRACE_ERROR( "SIG_SUA_CIA_CIA_COMP_REQ unexpected" );
#ifdef _SNDCP_DTI_2_
      MFREE_PRIM(sn_data_req);
#else /*_SNDCP_DTI_2_*/
      PFREE_DESC(sn_data_req);
#endif /*_SNDCP_DTI_2_*/      
      break;
  }
} /* sig_sua_cia_cia_comp_req() */

#endif /* CF_FAST_EXEC */


/*
+------------------------------------------------------------------------------
| Function    : sig_mg_cia_delete_npdus
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_MG_CIA_DELETE_NPDUS
|
| Parameters  : nsapi
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sig_mg_cia_delete_npdus (UBYTE nsapi)
{
  TRACE_ISIG( "sig_mg_cia_delete_npdus" );

  switch( GET_STATE(CIA) )
  {
    case CIA_DEFAULT:
      if (sndcp_data->cia.cur_cia_decomp_ind[nsapi] != NULL) {
#ifdef SNDCP_TRACE_ALL
        sndcp_data->cia.cia_decomp_ind_number[nsapi] --;
        TRACE_EVENT_P1("number of cia_decomp_ind: % d",
                       sndcp_data->cia.cia_decomp_ind_number[nsapi]);
#endif /* SNDCP_TRACE_ALL */
          /*
           * Currently assembled pdu is for given nsapi.
           */
        MFREE_PRIM(sndcp_data->cia.cur_cia_decomp_ind[nsapi]);
        sndcp_data->cia.cur_cia_decomp_ind[nsapi] = NULL;
      }
      break;
    default:
      TRACE_ERROR( "SIG_MG_CIA_DELETE_XID unexpected" );
      break;
  }
} /* SIG_MG_CIA_DELETE_NPDUS() */

#endif /* CF_FAST_EXEC */


/*
+------------------------------------------------------------------------------
| Function    : sig_mg_cia_new_xid
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_MG_CIA_NEW_XID
|
| Parameters  : new T_XID_BLOCK
|
+------------------------------------------------------------------------------
*/
#ifndef CF_FAST_EXEC

GLOBAL void sig_mg_cia_new_xid (T_XID_BLOCK* new_xid)
{
#ifdef TI_PS_FF_V42BIS
  T_XID_BLOCK* old_xid;
  U8  p0 = SNDCP_V42_DEFAULT_DIRECTION;
  U16 p1 = SNDCP_V42_DEFAULT_P1;
  U8  p2 = SNDCP_V42_DEFAULT_P2;

  old_xid = &(sndcp_data->cia.cur_xid_block);
#endif

  TRACE_ISIG( "sig_mg_cia_new_xid" );

  switch( GET_STATE(CIA) )
  {
    case CIA_DEFAULT:
      if (new_xid->vj.is_set) {
        if (new_xid->vj.s0_m_1_set) {
          cia_compress_init((UBYTE)(new_xid->vj.s0_m_1));
        }
      }
#ifdef TI_PS_FF_V42BIS
      if (new_xid->v42.is_set)
      {
        /* block is valid */
        if (new_xid->v42.p0_set)
        {
          p0 = new_xid->v42.p0;
          /* what have we to do, if p0 is not set? */
        }
        if (new_xid->v42.p1_set)
        {
          p1 = new_xid->v42.p1;
          /* what have we to do, if p1 is not set? */
        }
        if (new_xid->v42.p2_set)
        {
          p2 = new_xid->v42.p2;
          /* what have we to do, if p2 is not set? */
        }            
        
        if (new_xid->v42.nsapis_set && new_xid->v42.nsapis == 0)
        {
          /* no applicable NSAPI
           * turn off data compression in either direction
           */
          if (old_xid->v42.p0_set && old_xid->v42.p0 & 0x1) /* uplink */
          {
            TRACE_EVENT_P1("1 enc dico:%08x",sndcp_data->cia.enc);
            v42b_deinit(sndcp_data->cia.enc);
            MFREE(sndcp_data->cia.enc);
            TRACE_EVENT("uplink deinit");
          }
          if (old_xid->v42.p0_set && old_xid->v42.p0 & 0x2) /* downlink */
          {
            TRACE_EVENT_P1("1 dec dico:%08x",sndcp_data->cia.dec);
            v42b_deinit(sndcp_data->cia.dec);
            MFREE(sndcp_data->cia.dec);
            TRACE_EVENT("downlink deinit");
          }
        }
        else if (old_xid->v42.is_set)
        {
          /* currently we have a valid xid-block for data compression
           * we have to check the parameters 
           */
          
          /* we have to check the parameters */
          if (old_xid->v42.p0 != p0 ||
              old_xid->v42.p1 != p1 ||
              old_xid->v42.p2 != p2)
          {
            /* parameters have changed */
            if (old_xid->v42.p0_set && old_xid->v42.p0 & 0x1) /* uplink */
            {
              TRACE_EVENT_P1("2 enc dico:%08x",sndcp_data->cia.enc);
              v42b_deinit(sndcp_data->cia.enc);
              MFREE(sndcp_data->cia.enc);
              TRACE_EVENT("uplink deinit");
            }
            if (old_xid->v42.p0_set && old_xid->v42.p0 & 0x2) /* downlink */
            {
              TRACE_EVENT_P1("2 dec dico:%08x",sndcp_data->cia.dec);
              v42b_deinit(sndcp_data->cia.dec);
              MFREE(sndcp_data->cia.dec);
              TRACE_EVENT("uplink deinit");
            }
            /* we have to init with new parameters */
            if (p0 & 0x1)/* uplink */
            {
              TRACE_EVENT_P1("DICO_SIZE:%d",sizeof(T_V42B_DICO));
              MALLOC(sndcp_data->cia.enc, sizeof(T_V42B_DICO));
              TRACE_EVENT_P1("enc dico:%08x",sndcp_data->cia.enc);
              v42b_init(sndcp_data->cia.enc, p1, p2, 50, BANK_SIZE_512);
              TRACE_EVENT("uplink init");
            }
            if (p0 & 0x2)/* downlink */
            {
              TRACE_EVENT_P1("DICO_SIZE:%d",sizeof(T_V42B_DICO));
              MALLOC(sndcp_data->cia.dec, sizeof(T_V42B_DICO));
              v42b_init(sndcp_data->cia.dec, p1, p2, 0, BANK_SIZE_512);
              TRACE_EVENT_P1("dec dico:%08x",sndcp_data->cia.dec);
              TRACE_EVENT("downlink init");
            }     
          }
        }
        else
        {
          /* currently we have no valid xid-block for data comprssion */
          if (p0 & 0x1)/* uplink */
          {
            TRACE_EVENT_P1("DICO_SIZE:%d",sizeof(T_V42B_DICO));
            MALLOC(sndcp_data->cia.enc, sizeof(T_V42B_DICO));
            TRACE_EVENT_P1("enc dico:%08x",sndcp_data->cia.enc);
            v42b_init(sndcp_data->cia.enc, p1, p2, 50, BANK_SIZE_512);
            TRACE_EVENT("uplink init");
          }
          if (p0 & 0x2)/* downlink */
          {
            TRACE_EVENT_P1("DICO_SIZE:%d",sizeof(T_V42B_DICO));
            MALLOC(sndcp_data->cia.dec, sizeof(T_V42B_DICO));
            TRACE_EVENT_P1("dec dico:%08x",sndcp_data->cia.dec);
            v42b_init(sndcp_data->cia.dec, p1, p2, 0, BANK_SIZE_512);
            TRACE_EVENT("downlink init");
          }          
        }
      }
      else
      {
        if (old_xid->v42.is_set && old_xid->v42.nsapis_set && old_xid->v42.nsapis != 0)
        {
          /* we have no XID with V42 set */
          if (old_xid->v42.p0_set && old_xid->v42.p0 & 0x1) /* uplink */
          {
            TRACE_EVENT_P1("3 enc dico:%08x",sndcp_data->cia.enc);
            v42b_deinit(sndcp_data->cia.enc);
            MFREE(sndcp_data->cia.enc);
            TRACE_EVENT("uplink deinit");
          }
          if (old_xid->v42.p0_set && old_xid->v42.p0 & 0x2) /* downlink */
          {
            TRACE_EVENT_P1("3 dec dico:%08x",sndcp_data->cia.dec);
            v42b_deinit(sndcp_data->cia.dec);
            MFREE(sndcp_data->cia.dec);
            TRACE_EVENT("downlink deinit");
          }
        }
      }
#endif /* TI_PS_FF_V42BIS */
      sndcp_data->cia.cur_xid_block = *new_xid;
      break;
    default:
      TRACE_ERROR( "SIG_MG_CIA_NEW_XID unexpected" );
      break;
  }
} /* SIG_MG_CIA_NEW_XID() */

#endif /* CF_FAST_EXEC */

/*
+------------------------------------------------------------------------------
| Function    : sig_sd_cia_cia_decomp_req
+------------------------------------------------------------------------------
| Description : Handles the internal signal SIG_SD_CIA_TRANSFER_REQ
|               This function mekes a decision whether we are using data 
|               compression in downlink direction and calls the according
|               function.
|
| Parameters  :
|
+------------------------------------------------------------------------------
*/
/*#if defined(CF_FAST_EXEC) || defined(_SIMULATION_) || \
   defined(SNDCP_2to1) */

GLOBAL void sig_sd_cia_cia_decomp_req (T_LL_UNITDATA_IND* ll_unitdata_ind)/*UBYTE dcomp,
                                     T_pdu_ref pdu_ref,
                                     USHORT cur_seg_pos,
                                     T_LL_UNITDATA_IND* ll_unitdata_ind
                                    )*/
{
#ifdef TI_PS_FF_V42BIS
  U8 direction = 0;
  U8 nsapi;
#endif /* TI_PS_FF_V42BIS */
  TRACE_ISIG( "sig_sd_cia_cia_decomp_req" );
#ifdef TI_PS_FF_V42BIS  
  nsapi = (ll_unitdata_ind->sdu.buf[(ll_unitdata_ind->sdu.o_buf / 8)]) & 0xf;
#endif /* TI_PS_FF_V42BIS */   
  switch( GET_STATE(CIA) )
  {
    case CIA_DEFAULT:
#ifdef TI_PS_FF_V42BIS
      if (sndcp_data->cia.cur_xid_block.v42.is_set)
      {
        if (sndcp_data->cia.cur_xid_block.v42.p0_set)
        {
          direction = sndcp_data->cia.cur_xid_block.v42.p0;
          TRACE_EVENT_P1("dir: %d",direction);
        }
      }
      /*
       * Is dcomp in sdu equal to dcomp in cur_xid_block and downlink?
       */
      TRACE_EVENT_P1("our dcomp value: %d", sndcp_data->cia.cur_xid_block.v42.dcomp);
      TRACE_EVENT_P1("receipt dcomp value: %d", sndcp_data->cur_dcomp[nsapi]);
      if (sndcp_data->cur_dcomp[nsapi] == sndcp_data->cia.cur_xid_block.v42.dcomp && (direction & 0x2))
      {
        /*
         * Compression used
         */
        cia_sd_cci_decomp_req(/*pdu_ref, cur_seg_pos, */ll_unitdata_ind);

      } else {
        /*
         * No compression used, request will not be sent to CCI, but handled
         * in cia service.
         */
        cia_sd_cia_decomp_req (/*pdu_ref, cur_seg_pos, */ll_unitdata_ind);
      }
#else /* ! TI_PS_FF_V42BIS */
      cia_sd_cia_decomp_req (/*pdu_ref, cur_seg_pos, */ll_unitdata_ind);
#endif /* TI_PS_FF_V42BIS */

      break;
    default:
      TRACE_ERROR( "SIG_SD_CIA_TRANSFER_REQ unexpected" );
      break;
  }
} /* sig_sd_cia_cia_decomp_req() */
/*#endif */