view src/g23m-fad/ppp/ppp_lcpf.c @ 303:f76436d19a7a default tip

!GPRS config: fix long-standing AT+COPS chance hanging bug There has been a long-standing bug in FreeCalypso going back years: sometimes in the AT command bring-up sequence of an ACI-only MS, the AT+COPS command would produce only a power scan followed by cessation of protocol stack activity (only L1 ADC traces), instead of the expected network search sequence. This behaviour was seen in different FC firmware versions going back to Citrine, and seemed to follow some law of chance, not reliably repeatable. This bug has been tracked down and found to be specific to !GPRS configuration, stemming from our TCS2/TCS3 hybrid and reconstruction of !GPRS support that was bitrotten in TCS3.2/LoCosto version. ACI module psa_mms.c, needed only for !GPRS, was missing in the TCS3 version and had to be pulled from TCS2 - but as it turns out, there is a new field in the MMR_REG_REQ primitive that needs to be set correctly, and that psa_mms.c module is the place where this initialization needed to be added.
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 08 Jun 2023 08:23:37 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/* 
+----------------------------------------------------------------------------- 
|  Project :  
|  Modul   :  
+----------------------------------------------------------------------------- 
|  Copyright 2002 Texas Instruments Berlin, AG 
|                 All rights reserved. 
| 
|                 This file is confidential and a trade secret of Texas 
|                 Instruments Berlin, AG 
|                 The receipt of or possession of this file does not convey 
|                 any rights to reproduce or disclose its contents or to 
|                 manufacture, use, or sell anything it may describe, in 
|                 whole, or in part, without the specific written consent of 
|                 Texas Instruments Berlin, AG. 
+----------------------------------------------------------------------------- 
|  Purpose :  This modul is part of the entity PPP and implements all 
|             procedures and functions as described in the 
|             SDL-documentation (LCP-statemachine)
+----------------------------------------------------------------------------- 
*/ 

#ifndef PPP_LCPF_C
#define PPP_LCPF_C
#endif /* !PPP_LCPF_C */

#define ENTITY_PPP

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

#include "typedefs.h"   /* to get Condat data types */
#include "vsi.h"        /* to get a lot of macros */
#include "macdef.h"     /* to get a lot of macros */
#include "custom.h"     /* to get a lot of macros */
#include "gsm.h"        /* to get a lot of macros */
#include "cnf_ppp.h"    /* to get cnf-definitions */
#include "mon_ppp.h"    /* to get mon-definitions */
#include "prim.h"       /* to get the definitions of used SAP and directions */
#include "dti.h"        /* to get the DTILIB definitions */
#include "ppp.h"        /* to get the global entity definitions */

#include <string.h>     /* to get memcpy */
#include "ppp_arbf.h"   /* to get function interface from arb */
#include "ppp_capf.h"

#ifdef _SIMULATION_
#include <stdio.h>      /* to get sprintf */
#endif /* _SIMULATION_ */

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

#define TYPE_MRU                  1
#define TYPE_ACCM                 2
#define TYPE_AP                   3
#define TYPE_QP                   4
#define TYPE_MAGIC                5
#define TYPE_PFC                  7
#define TYPE_ACFC                 8
#define TYPE_FCS                  9

#define LENGTH_MRU                4
#define LENGTH_ACCM               6
#define LENGTH_AP_PAP             4
#define LENGTH_AP_CHAP            5
#define LENGTH_AP_MIN             4
#define LENGTH_AP_MAX             LENGTH_AP_CHAP
#define LENGTH_MAGIC              6
#define LENGTH_PFC                2
#define LENGTH_ACFC               2
#define LENGTH_FCS                3

                /*
                 * all other configuration options not yet supported
                 */
#define LCP_CONF_REQ_LENGTH_MAX   (4 +              \
                                   LENGTH_MRU +     \
                                   LENGTH_ACCM +    \
                                   LENGTH_AP_MAX +  \
                                   LENGTH_PFC +     \
                                   LENGTH_ACFC)
#define LCP_TERM_REQ_LENGTH       6

#define ALGORITHM_MD5             5

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

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

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



/*
+------------------------------------------------------------------------------
| Function    : lcp_init
+------------------------------------------------------------------------------
| Description : The function lcp_init() initialize Link Control Protocol (LCP)
|
| Parameters  : no parameters
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_init ()
{ 
  TRACE_FUNCTION( "lcp_init" );
  /*
   * initialize values
   */
  ppp_data->lcp.req_mru=PPP_MRU_DEFAULT;
  ppp_data->lcp.req_ap=PPP_AP_DEFAULT;
  ppp_data->lcp.req_accm=PPP_ACCM_DEFAULT;

  ppp_data->lcp.r_mru=PPP_MRU_DEFAULT;
  ppp_data->lcp.r_accm=PPP_ACCM_DEFAULT;
  ppp_data->lcp.r_pfc=PPP_PFC_DEFAULT;
  ppp_data->lcp.r_acfc=PPP_ACFC_DEFAULT;

  ppp_data->lcp.s_mru=PPP_MRU_DEFAULT;
  ppp_data->lcp.s_accm=PPP_ACCM_DEFAULT;
  ppp_data->lcp.s_pfc=PPP_PFC_DEFAULT;
  ppp_data->lcp.s_acfc=PPP_ACFC_DEFAULT;

  ppp_data->lcp.n_ap=PPP_AP_DEFAULT;

  ppp_data->lcp.s_rejected=0;

  ppp_data->lcp.nscri=0;
  ppp_data->lcp.nstri=0;
  ppp_data->lcp.nscji=0;

  ppp_data->lcp.scr=FALSE;
  ppp_data->lcp.str=FALSE;
  
  INIT_STATE( PPP_SERVICE_LCP , LCP_STATE );
} /* lcp_init() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_get_values
+------------------------------------------------------------------------------
| Description : The function lcp_get_values() returns negotiated values
|
| Parameters  : ptr_ap   - returns Authentication Protocol
|               ptr_mru  - returns Maximum Receive Unit
|               ptr_accm - returns Async Control Character Map
|               ptr_pfc  - returns Protocol Field Compression
|               ptr_acfc - returns Address and Control Field Compression
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_get_values (UBYTE*  ptr_ap, 
                            USHORT* ptr_mru, 
                            ULONG*  ptr_accm, 
                            UBYTE*  ptr_pfc, 
                            UBYTE*  ptr_acfc)
{
  TRACE_FUNCTION( "lcp_get_values" );

  *ptr_mru = ppp_data->lcp.r_mru;
  *ptr_accm = ppp_data->lcp.r_accm | ppp_data->lcp.s_accm;
  *ptr_ap   = ppp_data->lcp.n_ap;
  *ptr_pfc  = ppp_data->lcp.r_pfc;
  *ptr_acfc = ppp_data->lcp.r_acfc;

} /* lcp_get_values() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_fill_out_packet
+------------------------------------------------------------------------------
| Description : The function lcp_fill_out_packet() puts a LCP packet into 
|               the protocol configuration list
|
| Parameters  : pco_buf - pco list buffer
|               ptr_pos - position where to write the LCP packet, this value
|                         must get back to the calling funtion
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_fill_out_packet (UBYTE pco_buf[], USHORT* ptr_pos)
{
  USHORT  pos;
  USHORT  len_pos1, len_pos2;
  USHORT  mru;

  TRACE_FUNCTION( "lcp_fill_out_packet" );

  if((ppp_data->pco_mask & PPP_PCO_MASK_LCP_MRU) ||
     (ppp_data->pco_mask & PPP_PCO_MASK_LCP_AP)  ||
     (ppp_data->pco_mask & PPP_PCO_MASK_LCP_TWO))
  {
    pos = *ptr_pos;
#ifdef _SIMULATION_
    TRACE_EVENT_P3("parameters: pco_buf[]=%08x, ptr_pos=%08x, pos=%d",
                    pco_buf, 
                    ptr_pos, 
                    (int)pos);
#endif /* _SIMULATION_ */

    /*
     * create Configure-Request packet
     */
      /*
       * Protocol ID
       */
    pco_buf[pos] = PROTOCOL_LCP_MSB;
    pos++;
    pco_buf[pos] = PROTOCOL_LCP_LSB;
    pos++;
      /*
       * Length of Protocol contents (store the position)
       */
    len_pos1 = pos;
    pos++;
        /*
         * Code field
         */
    pco_buf[pos] = CODE_CONF_REQ;
    pos++;
        /*
         * Identifier field (some value)
         */
    pco_buf[pos] = 1;
    pos++;
        /*
         * Length field (store the position)
         */
    len_pos2 = pos;
    pos++;
    pos++;

    if(ppp_data->pco_mask & PPP_PCO_MASK_LCP_MRU)
    {
      /*
       * Maximum Receive Unit
       */
        /*
         * if PPP_PCO_MASK_LCP_TWO is set use always s_mru
         * if PPP_PCO_MASK_LCP_TWO is not set 
         * use the smaller one of s_mru and r_mru
         */
      if((ppp_data->pco_mask & PPP_PCO_MASK_LCP_TWO) ||
         (ppp_data->lcp.s_mru < ppp_data->lcp.r_mru))
        mru = ppp_data->lcp.s_mru;
      else
        mru = ppp_data->lcp.r_mru;
      pco_buf[pos]=TYPE_MRU;
      pos++;
      pco_buf[pos]=LENGTH_MRU;
      pos++;
      pco_buf[pos]=(UBYTE)(mru >> 8);
      pos++;
      pco_buf[pos]=(UBYTE)(mru & 0x00ff);
      pos++;
    }

    if(ppp_data->pco_mask & PPP_PCO_MASK_LCP_AP)
    {
            /*
             * Authentication Protocol
             */
      switch(ppp_data->lcp.n_ap)
      {
        case PPP_AP_PAP:
          pco_buf[pos]=TYPE_AP;
          pos++;
          pco_buf[pos]=LENGTH_AP_PAP;
          pos++;
          pco_buf[pos]=PROTOCOL_PAP_MSB;
          pos++;
          pco_buf[pos]=PROTOCOL_PAP_LSB;
          pos++;
          break;
        case PPP_AP_CHAP:
          pco_buf[pos]=TYPE_AP;
          pos++;
          pco_buf[pos]=LENGTH_AP_CHAP;
          pos++;
          pco_buf[pos]=PROTOCOL_CHAP_MSB;
          pos++;
          pco_buf[pos]=PROTOCOL_CHAP_LSB;
          pos++;
          pco_buf[pos]=ALGORITHM_MD5;
          pos++;
          break;
      }
    }
        /*
         * insert packet length
         */
#ifdef _SIMULATION_
    TRACE_EVENT_P3("len_pos1=%d, len_pos2=%d, pos=%d",
                    (int)len_pos1, 
                    (int)len_pos2, 
                    (int)pos);
#endif /* _SIMULATION_ */
    pco_buf[len_pos2] = 0;
    len_pos2++;
    pco_buf[len_pos2] = (UBYTE)(pos - len_pos2 + 3);
      /*
       * insert Length of Protocol Contents
       */
    pco_buf[len_pos1] = pco_buf[len_pos2];

    if(ppp_data->pco_mask & PPP_PCO_MASK_LCP_TWO)
    {
      /*
       * create client Configure-Request packet
       */
        /*
         * Protocol ID
         */
      pco_buf[pos] = PROTOCOL_LCP_MSB;
      pos++;
      pco_buf[pos] = PROTOCOL_LCP_LSB;
      pos++;
        /*
         * Length of Protocol contents (store the position)
         */
      len_pos1 = pos;
      pos++;
          /*
           * Code field
           */
      pco_buf[pos] = CODE_CONF_REQ;
      pos++;
          /*
           * Identifier field (some value)
           */
      pco_buf[pos] = 1;
      pos++;
          /*
           * Length field (store the position)
           */
      len_pos2 = pos;
      pos++;
      pos++;

      if(ppp_data->pco_mask & PPP_PCO_MASK_LCP_MRU)
      {
          /*
           * Maximum Receive Unit
           */
        mru = ppp_data->lcp.r_mru;
        pco_buf[pos]=TYPE_MRU;
        pos++;
        pco_buf[pos]=LENGTH_MRU;
        pos++;
        pco_buf[pos]=(UBYTE)(mru >> 8);
        pos++;
        pco_buf[pos]=(UBYTE)(mru & 0x00ff);
        pos++;
      }

          /*
           * insert packet length
           */
#ifdef _SIMULATION_
      TRACE_EVENT_P3("len_pos1=%d, len_pos2=%d, pos=%d",
                      (int)len_pos1, 
                      (int)len_pos2, 
                      (int)pos);
#endif /* _SIMULATION_ */
      pco_buf[len_pos2] = 0;
      len_pos2++;
      pco_buf[len_pos2] = (UBYTE)(pos - len_pos2 + 3);
        /*
         * insert Length of Protocol Contents
         */
      pco_buf[len_pos1] = pco_buf[len_pos2];
    }

#ifdef _SIMULATION_
    TRACE_EVENT_P6("pco_buf[%d]=%02x, pco_buf[%d]=%02x, pco_buf[%d]=%02x",
                    (int)(len_pos1),
                    pco_buf[len_pos1],
                    (int)(len_pos2 - 1),
                    pco_buf[len_pos2 - 1],
                    (int)len_pos2,
                    pco_buf[len_pos2]);
#endif /* _SIMULATION_ */
    /*
     * return new position
     */
    *ptr_pos=pos;
  }
} /* lcp_fill_out_packet() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_get_scr
+------------------------------------------------------------------------------
| Description : The function lcp_get_scr() returns a LCP
|               Configure Request packet
|
| Parameters  : ptr_packet - returns the Configure Request packet
|                            THE MEMORY FOR THE PACKET WILL ALLOCATED BY
|                            THIS FUNCTION
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_get_scr (T_desc2** ptr_packet)
{
  T_desc2* ret_desc;
  USHORT  len_pos;
  USHORT  pos;


  TRACE_FUNCTION( "lcp_get_scr" );

  /*
   * Allocate the necessary size for the data descriptor. The size is 
   * calculated as follows:
   * - take the size of a descriptor structure
   * - subtract one because of the array buffer[1] to get the size of
   *   descriptor control information
   * - add number of octets of descriptor data
   */
  MALLOC (ret_desc, (USHORT)(sizeof(T_desc2) - 1 + LCP_CONF_REQ_LENGTH_MAX));
  /*
   * fill the packet
   */
  ret_desc->next=(ULONG)NULL;
  pos=0;
    /*
     * Code field
     */
  ret_desc->buffer[pos]=CODE_CONF_REQ;
  pos++;
    /*
     * Identifier field
     */
  ret_desc->buffer[pos]=ppp_data->lcp.nscri;/*lint !e415 (Warning -- access of out-of-bounds pointer) */
  pos++;
    /*
     * Length field (store the position)
     */
  len_pos=pos;
  pos++;
  pos++;
      /*
       * Maximum Receive Unit
       */
  if(((ppp_data->lcp.s_rejected & (1UL << TYPE_MRU)) EQ 0) && 
     (ppp_data->lcp.s_mru NEQ PPP_MRU_DEFAULT))
  {
    ret_desc->buffer[pos]=TYPE_MRU;/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=LENGTH_MRU;/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->lcp.s_mru >> 8);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->lcp.s_mru & 0x00ff);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
    pos++;
  }
      /*
       * Async Control Character Map
       */
  if(((ppp_data->lcp.s_rejected & (1UL << TYPE_ACCM)) EQ 0) && 
     (ppp_data->lcp.s_accm NEQ PPP_ACCM_DEFAULT))
  {
    ret_desc->buffer[pos]=TYPE_ACCM;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=LENGTH_ACCM;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->lcp.s_accm >> 24);/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->lcp.s_accm >> 16) & 0x000000ff);/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->lcp.s_accm >>  8) & 0x000000ff);/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->lcp.s_accm & 0x000000ff);/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
  }
      /*
       * Authentication Protocol
       * (only in server mode)
       */
  if(((ppp_data->lcp.s_rejected & (1UL << TYPE_AP)) EQ 0) && 
     (ppp_data->mode EQ PPP_SERVER) &&
     (ppp_data->lcp.n_ap NEQ PPP_AP_DEFAULT))
    if(ppp_data->lcp.n_ap EQ PPP_AP_PAP)
    {
      ret_desc->buffer[pos]=TYPE_AP;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
      pos++;
      ret_desc->buffer[pos]=LENGTH_AP_PAP;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
      pos++;
      ret_desc->buffer[pos]=PROTOCOL_PAP_MSB;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
      pos++;
      ret_desc->buffer[pos]=PROTOCOL_PAP_LSB;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
      pos++;
    }
    else
    {
      ret_desc->buffer[pos]=TYPE_AP;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
      pos++;
      ret_desc->buffer[pos]=LENGTH_AP_CHAP;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
      pos++;
      ret_desc->buffer[pos]=PROTOCOL_CHAP_MSB;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
      pos++;
      ret_desc->buffer[pos]=PROTOCOL_CHAP_LSB;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
      pos++;
      ret_desc->buffer[pos]=ALGORITHM_MD5;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
      pos++;
    }
      /*
       * Protocol Field Compression
       */
  if(((ppp_data->lcp.s_rejected & (1UL << TYPE_PFC)) EQ 0) && 
     (ppp_data->lcp.s_pfc NEQ PPP_PFC_DEFAULT))
  {
    ret_desc->buffer[pos]=TYPE_PFC;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=LENGTH_PFC;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
  }
      /*
       * Address and Control Field Compression
       */
  if(((ppp_data->lcp.s_rejected & (1UL << TYPE_ACFC)) EQ 0) && 
     (ppp_data->lcp.s_acfc NEQ PPP_ACFC_DEFAULT))
  {
    ret_desc->buffer[pos]=TYPE_ACFC;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
    ret_desc->buffer[pos]=LENGTH_ACFC;/*lint !e661 !e662 (Warning -- Likely access/creation of out-of-bounds pointer) */
    pos++;
  }
  

  /*
   * insert packet length
   */
  ret_desc->len=pos;
  ret_desc->buffer[len_pos]=(UBYTE)(pos >> 8);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  len_pos++;
  ret_desc->buffer[len_pos]=(UBYTE)(pos & 0x00ff);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  
  /*
   * return the created packet
   */
  ppp_data->lcp.scr=TRUE;
  *ptr_packet=ret_desc;
  
} /* lcp_get_scr() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_get_str
+------------------------------------------------------------------------------
| Description : The function lcp_get_str() returns a LCP
|               Terminate Request packet
|
| Parameters  : ptr_packet - returns the Terminate Request packet
|                            THE MEMORY FOR THE PACKET WILL ALLOCATED BY
|                            THIS FUNCTION
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_get_str (T_desc2** ptr_packet)
{
  T_desc2* ret_desc;
  USHORT  pos;

  TRACE_FUNCTION( "lcp_get_str" );
  
  /*
   * Allocate the necessary size for the data descriptor. The size is 
   * calculated as follows:
   * - take the size of a descriptor structure
   * - subtract one because of the array buffer[1] to get the size of
   *   descriptor control information
   * - add number of octets of descriptor data
   */
  MALLOC (ret_desc, (USHORT)(sizeof(T_desc2) - 1 + LCP_TERM_REQ_LENGTH));
  /*
   * fill the packet
   */
  ret_desc->next = (ULONG)NULL;
  ret_desc->len  = LCP_TERM_REQ_LENGTH;
  pos            = 0;
    /*
     * Code field
     */
  ret_desc->buffer[pos] = CODE_TERM_REQ;
  pos++;
    /*
     * Identifier field
     */
  ret_desc->buffer[pos] = ppp_data->lcp.nstri;/*lint !e415 (Warning -- access of out-of-bounds pointer) */
  pos++;
    /*
     * Length field
     */
  ret_desc->buffer[pos] = 0;/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  pos++;
  ret_desc->buffer[pos] = LCP_TERM_REQ_LENGTH;/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  pos++;
    /*
     * Data field contains the error code
     */
  ret_desc->buffer[pos] = (U8)((ppp_data->ppp_cause >> 8) & 0x00ff);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  pos++;
  ret_desc->buffer[pos] = (U8)((ppp_data->ppp_cause)      & 0x00ff);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  pos++;

  /*
   * return the created packet
   */
  ppp_data->lcp.str = TRUE;
  *ptr_packet       = ret_desc;
} /* lcp_get_str() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rcr
+------------------------------------------------------------------------------
| Description : The function lcp_rcr() analyzes the given 
|               Configure Request packet and returns either FORWARD_RCRP or
|               FORWARD_RCRN depend on the result of the analysis. 
|               The packet pointer points to an appropriate response packet. 
|
| Parameters  : ptr_packet  - pointer to a Configure Request packet
|               forward     - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rcr (T_desc2** ptr_packet, UBYTE* isnew, UBYTE* forward)
{
  T_desc2* packet;
  USHORT  packet_len;
  UBYTE   type_len;
  USHORT  pos;
  USHORT  copy_pos;
  USHORT  analyzed;
  UBYTE   code_ret;
  USHORT  ap_id;
  UBYTE   error_found;

  TRACE_FUNCTION( "lcp_rcr" );
  
  /*
   * check for correct length field
   */
  packet=*ptr_packet;
  packet_len=packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len=packet_len << 8;
  packet_len+=packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len > packet->len) || (packet_len < 4))
  {
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * check consistence of length of packet and length of configuration options
   */
  pos=5;
  while(pos < packet_len)
  {
    if(packet->buffer[pos] < 2)
    {
      *forward=FORWARD_DISCARD;
      return;
    }
    pos += packet->buffer[pos];
  }
  if((pos - 1) NEQ packet_len)
  {
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * check whether it is a new identifier
   */
  *isnew=TRUE;
  if((ppp_data->lcp.rcr) && (ppp_data->lcp.lrcri EQ packet->buffer[1]))/*lint !e415 (Warning -- access of out-of-bounds pointer) */
    *isnew=FALSE;
  ppp_data->lcp.lrcri=packet->buffer[1];/*lint !e415 (Warning -- access of out-of-bounds pointer) */
  ppp_data->lcp.rcr=TRUE;
  /*
   * analyze configuration options
   */
  ppp_data->lcp.r_mru  = PPP_MRU_DEFAULT;
  ppp_data->lcp.r_accm = PPP_ACCM_DEFAULT;
  ppp_data->lcp.r_pfc  = PPP_PFC_DEFAULT;
  ppp_data->lcp.r_acfc = PPP_ACFC_DEFAULT;
  if(ppp_data->mode EQ PPP_CLIENT)
    ppp_data->lcp.n_ap=PPP_AP_DEFAULT;
  pos=4;
    /*
     * position where NAKed or Rejected configuration options are copied to
     */
  copy_pos=4;
    /*
     * code_ret contains actually the status of analysis
     * states are CODE_CONF_ACK, CODE_CONF_NAK and CODE_CONF_REJ
     * this state are also values for the Code-field in the return packet
     */
  code_ret=CODE_CONF_ACK;
    /*
     * analyzed is a bit field and marks all already analyzed
     * configuration options in order to reject all configuration options
     * which are listed more than once
     */
  analyzed=0;
  while(pos < packet_len)
  {
    type_len=packet->buffer[pos + 1];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
    switch(packet->buffer[pos])/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
    {
      /*
       * yet supported configuration options
       */
      case TYPE_MRU:
        ppp_data->lcp.r_mru = packet->buffer[pos + 2];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
        ppp_data->lcp.r_mru = (ppp_data->lcp.r_mru << 8);
        ppp_data->lcp.r_mru+= packet->buffer[pos + 3];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */

        switch(code_ret)
        {
          case CODE_CONF_ACK:
            if(((analyzed & (1UL << TYPE_MRU)) EQ 0) &&
               (type_len EQ LENGTH_MRU) && 
               (ppp_data->lcp.r_mru >= PPP_MRU_MIN))
            {
              analyzed|=(1UL << TYPE_MRU);
              pos+=LENGTH_MRU;
              break;
            }
            code_ret=CODE_CONF_NAK;
          case CODE_CONF_NAK:
            if((analyzed & (1UL << TYPE_MRU)) EQ 0)
            {
              analyzed|=(1UL << TYPE_MRU);

              error_found=FALSE;
              if(type_len < LENGTH_MRU)
              {
                T_desc2* temp_desc;

                /*
                 * create a new larger packet and copy the content
                 * of the old packet into the new
                 */
                MALLOC (temp_desc, (USHORT)(sizeof(T_desc2) - 1 
                                                           + packet_len 
                                                           + LENGTH_MRU
                                                           - type_len));
                temp_desc->next=packet->next;
                temp_desc->len=packet_len + LENGTH_MRU - type_len;
                memcpy(temp_desc->buffer, packet->buffer, pos);/*lint !e669 !e670 (Warning -- Possible data overrun, Possible access beyond array ) */
                memcpy(&temp_desc->buffer[pos + LENGTH_MRU - type_len], 
                       &packet->buffer[pos], packet_len - pos);/*lint !e669 !e670 !e662 (Warning -- Possible data overrun, Possible access beyond array ) */
                arb_discard_packet(packet);
                packet_len += (LENGTH_MRU - type_len);
                pos        += (LENGTH_MRU - type_len);
                packet=temp_desc;

                error_found=TRUE;
                ppp_data->lcp.r_mru=PPP_MRU_MIN;
              }
              else if(ppp_data->lcp.r_mru < PPP_MRU_MIN)
              {
                error_found=TRUE;
                ppp_data->lcp.r_mru=PPP_MRU_MIN;
              }
              else if(type_len > LENGTH_MRU)
              {
                error_found=TRUE;
              }
              if(error_found EQ TRUE)
              {
                packet->buffer[copy_pos]=TYPE_MRU;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                copy_pos++;
                packet->buffer[copy_pos]=LENGTH_MRU;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)(ppp_data->lcp.r_mru >> 8);/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)(ppp_data->lcp.r_mru & 0x00ff);/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                copy_pos++;
              }
              pos+= type_len;
              break;
            }
            code_ret = CODE_CONF_REJ;
            copy_pos = 4;
          case CODE_CONF_REJ:
            if((analyzed & (1UL << TYPE_MRU)) EQ 0)
            {
              analyzed|=(1UL << TYPE_MRU);
              pos+= type_len;
              break;
            }
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
        }
        break;
      case TYPE_ACCM:
        ppp_data->lcp.r_accm=packet->buffer[pos + 2];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
        ppp_data->lcp.r_accm=(ppp_data->lcp.r_accm << 8);
        ppp_data->lcp.r_accm+=packet->buffer[pos + 3];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
        ppp_data->lcp.r_accm=(ppp_data->lcp.r_accm << 8);
        ppp_data->lcp.r_accm+=packet->buffer[pos + 4];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
        ppp_data->lcp.r_accm=(ppp_data->lcp.r_accm << 8);
        ppp_data->lcp.r_accm+=packet->buffer[pos + 5];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */

        switch(code_ret)
        {
          case CODE_CONF_ACK:
            if(((analyzed & (1UL << TYPE_ACCM)) EQ 0) &&
               (type_len EQ LENGTH_ACCM))
            {
              analyzed|=(1UL << TYPE_ACCM);
              pos+=LENGTH_ACCM;
              break;
            }
            code_ret=CODE_CONF_NAK;
          case CODE_CONF_NAK:
            if((analyzed & (1UL << TYPE_ACCM)) EQ 0)
            {
              analyzed|=(1UL << TYPE_ACCM);

              error_found=FALSE;
              if(type_len < LENGTH_ACCM)
              {
                T_desc2* temp_desc;

                /*
                 * create a new larger packet and copy the content
                 * of the old packet into the new
                 */
                MALLOC (temp_desc, (USHORT)(sizeof(T_desc2) - 1 
                                                           + packet_len 
                                                           + LENGTH_ACCM
                                                           - type_len));
                temp_desc->next=packet->next;
                temp_desc->len=packet_len + LENGTH_ACCM - type_len;
                memcpy(temp_desc->buffer, packet->buffer, pos);/*lint !e669 !e670 (Warning -- Possible data overrun, Possible access beyond array ) */
                memcpy(&temp_desc->buffer[pos + LENGTH_ACCM - type_len], 
                       &packet->buffer[pos], packet_len - pos);/*lint !e669 !e670 !e662 (Warning -- Possible data overrun, Possible access beyond array ) */
                arb_discard_packet(packet);
                packet_len += (LENGTH_ACCM - type_len);
                pos        += (LENGTH_ACCM - type_len);
                packet=temp_desc;

                error_found=TRUE;
              }
              else if(type_len > LENGTH_ACCM)
              {
                error_found=TRUE;
              }
              if(error_found EQ TRUE)
              {
                memmove(&packet->buffer[copy_pos], 
                        &packet->buffer[pos],
                        LENGTH_ACCM);/*lint !e669 !e670 !e662 (Warning -- Possible data overrun, Possible access beyond array ) */
                packet->buffer[copy_pos + 1]=LENGTH_ACCM;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                copy_pos+=LENGTH_ACCM;
              }
              pos+=type_len;
              break;
            }
            code_ret = CODE_CONF_REJ;
            copy_pos = 4;
          case CODE_CONF_REJ:
            if((analyzed & (1UL << TYPE_ACCM)) EQ 0)
            {
              analyzed|=(1UL << TYPE_ACCM);
              pos+=type_len;
              break;
            }
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
        }
        break;
      case TYPE_AP:
        ap_id  = (packet->buffer[pos + 2]) << 8;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
        ap_id |= packet->buffer[pos + 3];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */

        switch(code_ret)
        {
          case CODE_CONF_ACK:
            if(((analyzed & (1UL << TYPE_AP)) EQ 0) &&
               (ppp_data->mode EQ PPP_CLIENT))
            {
              if((ap_id EQ DTI_PID_PAP) &&
                 (type_len EQ LENGTH_AP_PAP) &&
                 (ppp_data->lcp.req_ap EQ PPP_AP_PAP))
              {
                analyzed|=(1UL << TYPE_AP);
                pos+=type_len;
                ppp_data->lcp.n_ap = PPP_AP_PAP;
                break;
              }
              if((ap_id EQ DTI_PID_PAP) &&
                 (type_len EQ LENGTH_AP_PAP) &&
                 (ppp_data->lcp.req_ap EQ PPP_AP_AUTO))
              {
                analyzed|=(1UL << TYPE_AP);
                pos+=type_len;
                ppp_data->lcp.n_ap = PPP_AP_PAP;
                break;
              }
              if((ap_id EQ DTI_PID_CHAP) &&
                 (type_len EQ LENGTH_AP_CHAP) &&
                 (ppp_data->lcp.req_ap EQ PPP_AP_CHAP))
              {
                analyzed|=(1UL << TYPE_AP);
                pos+=type_len;
                ppp_data->lcp.n_ap = PPP_AP_CHAP;
                break;
              }
              if((ap_id EQ DTI_PID_CHAP) &&
                 (type_len EQ LENGTH_AP_CHAP) &&
                 (ppp_data->lcp.req_ap EQ PPP_AP_AUTO))
              {
                analyzed|=(1UL << TYPE_AP);
                pos+=type_len;
                ppp_data->lcp.n_ap = PPP_AP_CHAP;
                break;
              }
            }
            code_ret=CODE_CONF_NAK;
          case CODE_CONF_NAK:
            if(((analyzed & (1UL << TYPE_AP)) EQ 0) &&
               (ppp_data->mode EQ PPP_CLIENT) &&
               (ppp_data->lcp.req_ap NEQ PPP_AP_NO))
            {
              analyzed|=(1UL << TYPE_AP);

              error_found=FALSE;
              if(((ppp_data->lcp.req_ap EQ PPP_AP_PAP) && 
                  (type_len < LENGTH_AP_PAP)) || 
                 ((ppp_data->lcp.req_ap EQ PPP_AP_CHAP) && 
                  (type_len < LENGTH_AP_CHAP)))
              {
                T_desc2* temp_desc;

                /*
                 * create a new larger packet and copy the content
                 * of the old packet into the new
                 */
                if(ppp_data->lcp.req_ap EQ PPP_AP_PAP)
                {
                  MALLOC (temp_desc, (USHORT)(sizeof(T_desc2) - 1 
                                                             + packet_len 
                                                             + LENGTH_AP_PAP
                                                             - type_len));
                  temp_desc->len=packet_len + LENGTH_AP_PAP - type_len;
                  memcpy(&temp_desc->buffer[pos + LENGTH_AP_PAP - type_len],
                         &packet->buffer[pos], packet_len - pos);/*lint !e669 !e670 !e662 (Warning -- Possible data overrun, Possible access beyond array ) */
                  packet_len += (LENGTH_AP_PAP - type_len);
                  pos        += (LENGTH_AP_PAP - type_len);
                }
                else
                {
                  MALLOC (temp_desc, (USHORT)(sizeof(T_desc2) - 1 
                                                             + packet_len 
                                                             + LENGTH_AP_CHAP
                                                             - type_len));
                  temp_desc->len=packet_len + LENGTH_AP_CHAP - type_len;
                  memcpy(&temp_desc->buffer[pos + LENGTH_AP_CHAP - type_len],
                         &packet->buffer[pos], packet_len - pos);/*lint !e669 !e670 !e662 (Warning -- Possible data overrun, Possible access beyond array ) */
                  packet_len += (LENGTH_AP_CHAP - type_len);
                  pos        += (LENGTH_AP_CHAP - type_len);
                }
                temp_desc->next=packet->next;
                memcpy(temp_desc->buffer, packet->buffer, pos);/*lint !e669 !e670 (Warning -- Possible data overrun, Possible access beyond array ) */
                arb_discard_packet(packet);
                packet=temp_desc;

                error_found=TRUE;
              }
              else if(((ppp_data->lcp.req_ap EQ PPP_AP_PAP) && 
                       (ap_id NEQ DTI_PID_PAP)) || 
                      ((ppp_data->lcp.req_ap EQ PPP_AP_CHAP) && 
                       (ap_id NEQ DTI_PID_CHAP)))
              {
                error_found=TRUE;
              }
              else if(((ppp_data->lcp.req_ap EQ PPP_AP_PAP) && 
                       (type_len > LENGTH_AP_PAP)) || 
                      ((ppp_data->lcp.req_ap EQ PPP_AP_CHAP) && 
                       (type_len > LENGTH_AP_CHAP)))
              {
                error_found=TRUE;
              }
              if(error_found EQ TRUE)
              {
                packet->buffer[copy_pos]=TYPE_AP;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                copy_pos++;
                if(ppp_data->lcp.req_ap EQ PPP_AP_PAP)
                {
                  packet->buffer[copy_pos]=LENGTH_AP_PAP;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                  copy_pos++;
                  packet->buffer[copy_pos]=PROTOCOL_PAP_MSB;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                  copy_pos++;
                  packet->buffer[copy_pos]=PROTOCOL_PAP_LSB;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                  copy_pos++;
                }
                else
                {
                  packet->buffer[copy_pos]=LENGTH_AP_CHAP;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                  copy_pos++;
                  packet->buffer[copy_pos]=PROTOCOL_CHAP_MSB;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                  copy_pos++;
                  packet->buffer[copy_pos]=PROTOCOL_CHAP_LSB;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                  copy_pos++;
                  packet->buffer[copy_pos]=ALGORITHM_MD5;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                  copy_pos++;
                }
              }
              pos+=type_len;
              break;
            }
            code_ret=CODE_CONF_REJ;
            copy_pos=4;
          case CODE_CONF_REJ:
            if(((analyzed & (1UL << TYPE_AP)) EQ 0) &&
               (ppp_data->mode EQ PPP_CLIENT) &&
               (ppp_data->lcp.req_ap NEQ PPP_AP_NO))
            {
              analyzed|=(1UL << TYPE_AP);
              pos+=type_len;
              break;
            }
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
        }
        break;
      case TYPE_PFC:
        ppp_data->lcp.r_pfc=TRUE;

        switch(code_ret)
        {
          case CODE_CONF_ACK:
            if(((analyzed & (1UL << TYPE_PFC)) EQ 0) &&
               (type_len EQ LENGTH_PFC))
            {
              analyzed|=(1UL << TYPE_PFC);
              pos+=LENGTH_PFC;
              break;
            }
            code_ret=CODE_CONF_NAK;
          case CODE_CONF_NAK:
            if((analyzed & (1UL << TYPE_PFC)) EQ 0)
            {
              analyzed|=(1UL << TYPE_PFC);

              if(type_len > LENGTH_PFC)
              {
                memmove(&packet->buffer[copy_pos], 
                        &packet->buffer[pos],
                        LENGTH_PFC);/*lint !e669 !e670 !e662 (Warning -- Possible data overrun, Possible access beyond array ) */
                packet->buffer[copy_pos + 1]=LENGTH_PFC;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                copy_pos+=LENGTH_PFC;
              }
              pos+=type_len;
              break;
            }
            code_ret=CODE_CONF_REJ;
            copy_pos=4;
          case CODE_CONF_REJ:
            if((analyzed & (1UL << TYPE_PFC)) EQ 0)
            {
              analyzed|=(1UL << TYPE_PFC);
              pos+=type_len;
              break;
            }
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
        }
        break;
      case TYPE_ACFC:
        ppp_data->lcp.r_acfc=TRUE;

        switch(code_ret)
        {
          case CODE_CONF_ACK:
            if(((analyzed & (1UL << TYPE_ACFC)) EQ 0) &&
               (type_len EQ LENGTH_ACFC))
            {
              analyzed|=(1UL << TYPE_ACFC);
              pos+=LENGTH_ACFC;
              break;
            }
            code_ret=CODE_CONF_NAK;
          case CODE_CONF_NAK:
            if((analyzed & (1UL << TYPE_ACFC)) EQ 0)
            {
              analyzed|=(1UL << TYPE_ACFC);

              if(type_len > LENGTH_ACFC)
              {
                memmove(&packet->buffer[copy_pos], 
                        &packet->buffer[pos],
                        LENGTH_ACFC);/*lint !e669 !e670 !e662 (Warning -- Possible data overrun, Possible access beyond array ) */
                packet->buffer[copy_pos + 1]=LENGTH_ACFC;/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
                copy_pos+=LENGTH_ACFC;
              }
              pos+=type_len;
              break;
            }
            code_ret=CODE_CONF_REJ;
            copy_pos=4;
          case CODE_CONF_REJ:
            if((analyzed & (1UL << TYPE_ACFC)) EQ 0)
            {
              analyzed|=(1UL << TYPE_ACFC);
              pos+=type_len;
              break;
            }
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
        }
        break;
      default:
        switch(code_ret)
        {
          case CODE_CONF_ACK:
          case CODE_CONF_NAK:
            code_ret=CODE_CONF_REJ;
            copy_pos=4;
            /* fall through */
          default:
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
        }
    }
  }
  /*
   * set new Code field in return packet
   */
  packet->buffer[0]=code_ret;
  *ptr_packet=packet;

  if(copy_pos > 4)
  {
    /*
     * some configuration options are not acceptable
     */
    *forward=FORWARD_RCRN;
      /*
       * set new Length field
       */
    packet->len=copy_pos;
    packet->buffer[2]=(UBYTE)(copy_pos >> 8);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
    packet->buffer[3]=(UBYTE)(copy_pos & 0x00ff);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
    return;
  }

#ifdef _SIMULATION_
  ppp_trace_desc(packet);
#endif
  /*
   * all configuration options are acceptable
   */
  *forward=FORWARD_RCRP;
} /* lcp_rcr() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rca
+------------------------------------------------------------------------------
| Description : The function lcp_rca() checks whether the given 
|               Configure Ack packet is valid and if so it returns
|               FORWARD_RCA.
|
| Parameters  : packet  - Configure Ack packet
|               forward - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rca (T_desc2* packet, UBYTE* forward)
{ 
  USHORT  packet_len;

  TRACE_FUNCTION( "lcp_rca" );

  packet_len=packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len=packet_len << 8;
  packet_len+=packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len < 4) || (packet_len > packet->len))
  {
    *forward=FORWARD_DISCARD;
    return;
  }

  if((ppp_data->lcp.scr EQ FALSE) || 
     (packet->buffer[1] NEQ ppp_data->lcp.nscri))/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  {
    /*
     * invalid packet
     */
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * acceptable packet
   */
  arb_discard_packet(packet);
  ppp_data->lcp.nscri++;
  *forward=FORWARD_RCA;
} /* lcp_rca() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rcn
+------------------------------------------------------------------------------
| Description : The function lcp_rcn() analyze the given 
|               Configure Nak packet, changes some requested values and returns
|               FORWARD_RCN
|               The packet pointer points to an appropriate response packet.
|
| Parameters  : ptr_packet - Configure Nak packet
|               forward    - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rcn (T_desc2** ptr_packet, UBYTE* forward)
{ 
  T_desc2* packet;
  USHORT   packet_len;
  UBYTE    type_len;
  USHORT   pos;
  USHORT   mru;
  ULONG    accm;

  TRACE_FUNCTION( "lcp_rcn" );
  
  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len = packet_len << 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len > packet->len) || (packet_len < 4))
  {
    *forward=FORWARD_DISCARD;
    return;
  }

  if((ppp_data->lcp.scr EQ FALSE) || 
     (packet->buffer[1] NEQ ppp_data->lcp.nscri))/*lint !e415  (Warning -- access of out-of-bounds pointer) */
  {
    /*
     * invalid packet
     */
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * check consistence of length of packet and length of configuration options
   */
  pos=5;
  while(pos < packet_len)
  {
    if(packet->buffer[pos] < 2)
    {
      *forward=FORWARD_DISCARD;
      return;
    }
    pos += packet->buffer[pos];
  }
  if((pos - 1) NEQ packet_len)
  {
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * analyze configuration options
   */
  pos=4;
  while(pos < packet_len)
  {
    type_len=packet->buffer[pos + 1];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
    switch(packet->buffer[pos])/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
    {
      /*
       * yet supported configuration options
       */
      case TYPE_MRU:
        mru = packet->buffer[pos + 2];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
        mru = mru << 8;
        mru+= packet->buffer[pos + 3];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */

        if((type_len EQ LENGTH_MRU) && 
           (mru >= PPP_MRU_MIN) &&
           (mru <= ppp_data->lcp.req_mru))
        {
          /*
           * clear reject flag and set new mru value
           */
          ppp_data->lcp.s_rejected &= ~(1UL << TYPE_MRU);
          ppp_data->lcp.s_mru=mru;
        }
        break;
      case TYPE_ACCM:
        if(type_len EQ LENGTH_ACCM)
        {
          accm=packet->buffer[pos + 2];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
          accm=accm << 8;
          accm+=packet->buffer[pos + 3];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
          accm=accm << 8;
          accm+=packet->buffer[pos + 4];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
          accm=accm << 8;
          accm+=packet->buffer[pos + 5];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */

          /*
           * clear reject flag and set new accm value
           */
          ppp_data->lcp.s_rejected &= ~(1UL << TYPE_ACCM);
          ppp_data->lcp.s_accm |= accm;
        }
        break;
      case TYPE_AP:
        if(ppp_data->lcp.n_ap EQ PPP_AP_CHAP)
        {
          TRACE_EVENT("LCP: CHAP rejected by client");
        }
        else if(ppp_data->lcp.n_ap EQ PPP_AP_PAP)
        {
          TRACE_EVENT("LCP: PAP rejected by client");
        }
        if((ppp_data->lcp.req_ap EQ PPP_AP_AUTO) &&
           (ppp_data->mode EQ PPP_SERVER))
        {
          /*
           * clear reject flag ans set new authentication protocol value
           */
          ppp_data->lcp.s_rejected &= ~(1UL << TYPE_AP);

          if((packet->buffer[pos + 2] EQ PROTOCOL_CHAP_MSB) &&
             (packet->buffer[pos + 3] EQ PROTOCOL_CHAP_LSB))/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
          {
            ppp_data->lcp.n_ap=PPP_AP_CHAP;
          }
          else if((packet->buffer[pos + 2] EQ PROTOCOL_PAP_MSB) &&
                  (packet->buffer[pos + 3] EQ PROTOCOL_PAP_LSB))/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
          {
            ppp_data->lcp.n_ap=PPP_AP_PAP;
          }
          else
          {
            ppp_data->lcp.n_ap=PPP_AP_NO;
          }
        }
        break;
      case TYPE_PFC:
        if(type_len EQ LENGTH_PFC)
        {
          /*
           * clear reject flag ans set new pfc value
           */
          ppp_data->lcp.s_rejected &= ~(1UL << TYPE_PFC);
          ppp_data->lcp.s_pfc=TRUE;
        }
        break;
      case TYPE_ACFC:
        if(type_len EQ LENGTH_ACFC)
        {
          /*
           * clear reject flag ans set new acfc value
           */
          ppp_data->lcp.s_rejected &= ~(1UL << TYPE_ACFC);
          ppp_data->lcp.s_acfc=TRUE;
        }
        break;
    }
    pos+=type_len;
  }
  /*
   * free this packet and create a new with changed configuration options
   */
  arb_discard_packet(packet);
  *forward=FORWARD_RCN;
  ppp_data->lcp.nscri++;
  lcp_get_scr(&packet);
  *ptr_packet=packet;
} /* lcp_rcn() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rcj
+------------------------------------------------------------------------------
| Description : The function lcp_rcj() analyze the given 
|               Configure Reject packet, marks some values as rejected and
|               returns FORWARD_RCJ
|               The packet pointer points to an appropriate response packet.
|
| Parameters  : ptr_packet  - pointer to a Configure Reject packet
|               forward     - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rcj (T_desc2** ptr_packet, UBYTE* forward)
{
  T_desc2* packet;
  USHORT  packet_len;
  UBYTE   type_len;
  USHORT  pos;

  TRACE_FUNCTION( "lcp_rcj" );
  
  /*
   * check for correct length field
   */
  packet=*ptr_packet;
  packet_len=packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len=packet_len << 8;
  packet_len+=packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len > packet->len) || (packet_len < 4))
  {
    *forward=FORWARD_DISCARD;
    return;
  }

  if((ppp_data->lcp.scr EQ FALSE) || 
     (packet->buffer[1] NEQ ppp_data->lcp.nscri))/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  {
    /*
     * invalid packet
     */
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * check consistence of length of packet and length of configuration options
   */
  pos=5;
  while(pos < packet_len)
  {
    if(packet->buffer[pos] < 2)
    {
      *forward=FORWARD_DISCARD;
      return;
    }
    pos += packet->buffer[pos];
  }
  if((pos - 1) NEQ packet_len)
  {
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * analyze configuration options
   */
  pos=4;
  while(pos < packet_len)
  {
    type_len=packet->buffer[pos + 1];/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
    switch(packet->buffer[pos])/*lint !e661 !e662 (Warning -- Possible access/creation of out-of-bounds pointer) */
    {
      /*
       * yet supported configuration options
       */
      case TYPE_MRU:
        ppp_data->lcp.s_rejected |= (1UL << TYPE_MRU);
        break;
      case TYPE_ACCM:
        ppp_data->lcp.s_rejected |= (1UL << TYPE_ACCM);
        break;
      case TYPE_PFC:
        ppp_data->lcp.s_rejected |= (1UL << TYPE_PFC);
        break;
      case TYPE_ACFC:
        ppp_data->lcp.s_rejected |= (1UL << TYPE_ACFC);
        break;
      case TYPE_AP:
        if(ppp_data->lcp.n_ap EQ PPP_AP_CHAP)
        {
          TRACE_EVENT("LCP: CHAP rejected by client");
        }
        else if(ppp_data->lcp.n_ap EQ PPP_AP_PAP)
        {
          TRACE_EVENT("LCP: PAP rejected by client");
        }
        if((ppp_data->lcp.req_ap EQ PPP_AP_AUTO) &&
           (ppp_data->mode EQ PPP_SERVER))
        {
          ppp_data->lcp.s_rejected |= (1UL << TYPE_AP);
        }
        break;
    }
    pos+=type_len;
  }
  /*
   * free this packet and create a new with changed configuration options
   */
  arb_discard_packet(packet);
  *forward=FORWARD_RCN;
  ppp_data->lcp.nscri++;
  lcp_get_scr(&packet);
  *ptr_packet=packet;
} /* lcp_rcj() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rtr
+------------------------------------------------------------------------------
| Description : The function lcp_rtr() creates a Terminate Ack packet. 
|
| Parameters  : ptr_packet  - pointer to a Terminate Request packet
|               forward     - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rtr (T_desc2** ptr_packet, UBYTE* forward)
{ 
  T_desc2* packet;
  USHORT  packet_len;

  TRACE_FUNCTION( "lcp_rtr" );
  
  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len = packet_len << 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len < 4) || (packet_len > packet->len))
  {
    *forward=FORWARD_DISCARD;
    return;
  }

  /*
   * change code field
   */
  packet->buffer[0]=CODE_TERM_ACK;
  
  *forward=FORWARD_RTR;
} /* lcp_rtr() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rta
+------------------------------------------------------------------------------
| Description : The function lcp_rta() checks whether the given 
|               Terminate Ack packet is valid and if so it returns
|               FORWARD_RTA
|
| Parameters  : packet  - Terminate Ack packet
|               forward - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rta (T_desc2* packet, UBYTE* forward)
{ 
  USHORT  packet_len;

  TRACE_FUNCTION( "lcp_rta" );
  
  /*
   * check for correct length field
   */
  packet_len = packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len = packet_len << 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len < 4) || (packet_len > packet->len))
  {
    *forward=FORWARD_DISCARD;
    return;
  }

  if((ppp_data->lcp.str EQ FALSE) || 
     (packet->buffer[1] NEQ ppp_data->lcp.nstri))/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  {
    /*
     * invalid packet
     */
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * acceptable packet
   */
  arb_discard_packet(packet);
  ppp_data->lcp.nstri++;
  *forward=FORWARD_RTA;
} /* lcp_rta() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rxj
+------------------------------------------------------------------------------
| Description : The function lcp_rxj() analyzes whether the given Code Reject
|               is acceptable. If not it returns FORWARD_RXJN
|
| Parameters  : ptr_packet - Pointer to a Code Reject packet
|               forward    - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rxj (T_desc2** ptr_packet, UBYTE* forward)
{
  USHORT  packet_len;
  T_desc2* packet;

  TRACE_FUNCTION( "lcp_rxj" );
  
  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len = packet_len << 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len < 5) || (packet_len > packet->len))
  {
    *forward=FORWARD_DISCARD;
    return;
  }
  
  switch(packet->buffer[4])/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  {
    case CODE_CONF_REQ:
    case CODE_CONF_REJ:
    case CODE_CONF_NAK:
    case CODE_CONF_ACK:
    case CODE_TERM_REQ:
    case CODE_TERM_ACK:
    case CODE_CODE_REJ:
    case CODE_PROT_REJ:
      arb_discard_packet(packet);
      ppp_data->lcp.nstri++;
      lcp_get_str(&packet);
      *ptr_packet=packet;
      *forward=FORWARD_RXJN;
      break;
    default:
      *forward=FORWARD_DISCARD;
      break;
  }
} /* lcp_rxj() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rpj
+------------------------------------------------------------------------------
| Description : The function lcp_rpj() analyzes which protocol is rejected.
|
| Parameters  : packet  - Protocol Reject packet
|               forward - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rpj (T_desc2* packet, UBYTE* forward)
{
  USHORT  packet_len;
  USHORT  rej_protocol;

  TRACE_FUNCTION( "lcp_rpj" );
  
  /*
   * check for correct length field
   */
  packet_len = packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len = packet_len << 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len < 6) || (packet_len > packet->len))
  {
    *forward=FORWARD_DISCARD;
    return;
  }

  /*
   * get rejected protocol
   */
  rej_protocol=packet->buffer[4];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  rej_protocol=rej_protocol << 8;
  rej_protocol+=packet->buffer[5];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */

  /* 
   * analyze rejected protocol
   */
  switch(rej_protocol)
  {
    case DTI_PID_LCP:
      arb_discard_packet(packet);
      *forward=FORWARD_RPJ_LCP;
      break;
    case DTI_PID_PAP:
      arb_discard_packet(packet);
      *forward=FORWARD_RPJ_PAP;
      break;
    case DTI_PID_CHAP:
      arb_discard_packet(packet);
      *forward=FORWARD_RPJ_CHAP;
      break;
    case DTI_PID_IPCP:
      arb_discard_packet(packet);
      *forward=FORWARD_RPJ_IPCP;
      break;
    case DTI_PID_IP:
      arb_discard_packet(packet);
      *forward=FORWARD_RPJ_IP;
      break;
    case DTI_PID_CTCP:
      arb_discard_packet(packet);
      *forward=FORWARD_RPJ_CTCP;
      break;
    case DTI_PID_UTCP:
      arb_discard_packet(packet);
      *forward=FORWARD_RPJ_UTCP;
      break;
    default:
      *forward=FORWARD_DISCARD;
      break;
  }
} /* lcp_rpj() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rer
+------------------------------------------------------------------------------
| Description : The function lcp_rer() creates an Echo Reply
|
| Parameters  : ptr_packet - Echo Request packet
|               forward    - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rer (T_desc2** ptr_packet, UBYTE* forward)
{ 
  T_desc2* packet;
  USHORT  packet_len;

  TRACE_FUNCTION( "lcp_rer" );
  
  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len = packet_len << 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len < 8) || (packet_len > packet->len))
  {
    *forward=FORWARD_DISCARD;
    return;
  }

  /* 
   * insert zero for magic number because we not yet support magic number
   * negotiation
   */
  packet->buffer[4]=0;/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet->buffer[5]=0;/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet->buffer[6]=0;/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet->buffer[7]=0;/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */

  /*
   * change Code field
   */
  packet->buffer[0]=CODE_ECHO_REP;

  /*
   * set return value
   */
  *forward=FORWARD_RER;
} /* lcp_rer() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_rep_rdr
+------------------------------------------------------------------------------
| Description : The function lcp_rep_rdr() just analyzes the given 
|               Magic Number.
|
| Parameters  : packet  - Echo Reply packet
|               forward - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_rep_rdr (T_desc2* packet, UBYTE* forward)
{ 
  TRACE_FUNCTION( "lcp_rep_rdr" );
  
  *forward=FORWARD_DISCARD;
} /* lcp_rep_rdr() */



/*
+------------------------------------------------------------------------------
| Function    : lcp_ruc
+------------------------------------------------------------------------------
| Description : The function lcp_ruc() creates a Code Reject packet and returns 
|               FORWARD_RUC.
|
| Parameters  : ptr_packet - packet with unknown code
|               forward    - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void lcp_ruc (T_desc2** ptr_packet, UBYTE* forward)
{ 
  T_desc2* packet;
  T_desc2* temp_desc;
  USHORT  packet_len;

  TRACE_FUNCTION( "lcp_ruc" );
  
  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet_len = packet_len << 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  if((packet_len < 4)  || (packet_len > packet->len))
  {
    *forward=FORWARD_DISCARD;
    return;
  }

  /*
   * create a new larger packet and copy the content
   * of the old packet into the new
   */
  packet_len+=4;
  if(packet_len > PPP_MRU_MIN)
    packet_len = PPP_MRU_MIN;
  MALLOC (temp_desc, (USHORT)(sizeof(T_desc2) - 1 + packet_len));

  temp_desc->next = packet->next;
  temp_desc->len  = packet_len;
  memcpy(&temp_desc->buffer[4], packet->buffer, packet_len - 4);/*lint !e669 !e670 !e416 (Warning -- Possible data overrun, Possible access beyond array ) */
  arb_discard_packet(packet);
  packet = temp_desc;

  /* 
   * fill the first bytes to create a Code Reject
   */
  packet->buffer[0] = CODE_CODE_REJ;
  ppp_data->lcp.nscji++;
  packet->buffer[1] = ppp_data->lcp.nscji;/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet->buffer[2] = (UBYTE)(packet_len >> 8);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */
  packet->buffer[3] = (UBYTE)(packet_len & 0x00ff);/*lint !e415 !e416 (Warning -- access/creation of out-of-bounds pointer) */

  /*
   * set return values
   */
  *ptr_packet = packet;
  *forward    = FORWARD_RUC;

} /* lcp_ruc() */