view src/g23m-fad/ppp/ppp_lcpf.c @ 19:aa868a5dcfd7

blobs: very few!
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 07:38:28 +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() */