view src/g23m-fad/ppp/ppp_ncpf.c @ 337:0df0668f8bea

FCHG: task core function implemented
author Mychaela Falconia <falcon@freecalypso.org>
date Thu, 14 Dec 2017 21:47:40 +0000
parents 90eb61ecd093
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 (NCP-statemachine)
+-----------------------------------------------------------------------------
*/

#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 "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 */

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

#define TYPE_HC                   2
#define TYPE_IP                   3
#define TYPE_PDNS                 129
#define TYPE_SDNS                 131
#define TYPE_ADJUST               125

#define MASK_TYPE_HC              TYPE_HC
#define MASK_TYPE_IP              TYPE_IP
#define MASK_TYPE_PDNS            (TYPE_PDNS - TYPE_ADJUST)
#define MASK_TYPE_SDNS            (TYPE_SDNS - TYPE_ADJUST)

#define LENGTH_HC_VJ              6
#define LENGTH_HC_MAX             LENGTH_HC_VJ
#define LENGTH_IP                 6
#define LENGTH_PDNS               6
#define LENGTH_SDNS               6

#define NCP_CONF_REQ_LENGTH_MAX   (4 +              \
                                   LENGTH_HC_MAX +  \
                                   LENGTH_IP +      \
                                   LENGTH_PDNS +    \
                                   LENGTH_SDNS)
#define NCP_TERM_REQ_LENGTH       6

#define PPP_CSID_YES              1

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

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

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



/*
+------------------------------------------------------------------------------
| Function    : ncp_init
+------------------------------------------------------------------------------
| Description : The function ncp_init() initialize Network Control Protocol
|
| Parameters  : no parameters
|
+------------------------------------------------------------------------------
*/
GLOBAL void ncp_init ()
{
  TRACE_FUNCTION( "ncp_init" );
  /*
   * initialize values
   */
  ppp_data->ncp.req_hc      = PPP_HC_DEFAULT;
  ppp_data->ncp.req_msid    = PPP_MSID_DEFAULT;
  ppp_data->ncp.req_ip      = PPP_IP_DEFAULT;
  ppp_data->ncp.req_pdns    = PPP_PDNS_DEFAULT;
  ppp_data->ncp.req_sdns    = PPP_SDNS_DEFAULT;
  ppp_data->ncp.req_gateway = PPP_GATEWAY_DEFAULT;

  ppp_data->ncp.s_hc      = PPP_HC_DEFAULT;
  ppp_data->ncp.s_msid    = PPP_MSID_DEFAULT;
  ppp_data->ncp.r_hc      = PPP_HC_DEFAULT;
  ppp_data->ncp.r_msid    = PPP_MSID_DEFAULT;
  ppp_data->ncp.n_ip      = PPP_IP_DEFAULT;
  ppp_data->ncp.n_pdns    = PPP_PDNS_DEFAULT;
  ppp_data->ncp.n_sdns    = PPP_SDNS_DEFAULT;
  ppp_data->ncp.n_gateway = PPP_GATEWAY_DEFAULT;

  ppp_data->ncp.s_rejected = 0;

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

  ppp_data->ncp.scr=FALSE;
  ppp_data->ncp.str=FALSE;
  ppp_data->ncp.rcr=FALSE;

  INIT_STATE( PPP_SERVICE_NCP , NCP_STATE );
} /* ncp_init() */



/*
+------------------------------------------------------------------------------
| Function    : ncp_get_values
+------------------------------------------------------------------------------
| Description : The function ncp_get_values() returns negotiated values
|
| Parameters  : ptr_hc   - returns IP Header Compression
|               ptr_msid - returns max slot identifier
|               ptr_ip   - returns IP address
|               ptr_pdns - returns primary DNS server address
|               ptr_pdns - returns secondary DNS server address
|
+------------------------------------------------------------------------------
*/
GLOBAL void ncp_get_values (UBYTE* ptr_hc, UBYTE* ptr_msid, ULONG* ptr_ip,
                            ULONG* ptr_pdns, ULONG* ptr_sdns)
{
  TRACE_FUNCTION( "ncp_get_values" );

  *ptr_hc   = ppp_data->ncp.r_hc;
  if(ppp_data->ncp.r_msid < ppp_data->ncp.s_msid)
    *ptr_msid = ppp_data->ncp.r_msid;
  else
    *ptr_msid = ppp_data->ncp.s_msid;
  *ptr_ip   = ppp_data->ncp.n_ip;
  *ptr_pdns = ppp_data->ncp.n_pdns;
  *ptr_sdns = ppp_data->ncp.n_sdns;

} /* ncp_get_values() */



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

  TRACE_FUNCTION( "ncp_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 + NCP_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->ncp.nscri;/*lint !e415 access of out-of-bounds pointer */
  pos++;
    /*
     * Length field (store the position)
     */
  len_pos=pos;
  pos++;
  pos++;
      /*
       * Header Compression Protocol (only server mode)
       */
  if(((ppp_data->ncp.s_rejected & (1UL << MASK_TYPE_HC)) EQ 0) &&
     (ppp_data->ncp.s_hc NEQ PPP_HC_DEFAULT))
  {
    if(ppp_data->ncp.s_hc EQ PPP_HC_VJ)
    {
      ret_desc->buffer[pos] = TYPE_HC;/*lint !e415 !e416 access of out-of-bounds pointer */
      pos++;
      ret_desc->buffer[pos] = LENGTH_HC_VJ;/*lint !e415 !e416 access of out-of-bounds pointer */
      pos++;
      ret_desc->buffer[pos] = PROTOCOL_VJ_MSB;/*lint !e415 !e416 access of out-of-bounds pointer */
      pos++;
      ret_desc->buffer[pos] = PROTOCOL_VJ_LSB;/*lint !e415 !e416 access of out-of-bounds pointer */
      pos++;
      ret_desc->buffer[pos] = ppp_data->ncp.s_msid;/*lint !e415 !e416 access of out-of-bounds pointer */
      pos++;
      ret_desc->buffer[pos] = PPP_CSID_YES;/*lint !e415 !e416 access of out-of-bounds pointer */
      pos++;
    }
    /*
     * include additional header compression protocols
     */
  }
      /*
       * IP Address (only client mode)
       */
  if(((ppp_data->ncp.s_rejected & (1UL << MASK_TYPE_IP)) EQ 0) &&
     (ppp_data->mode EQ PPP_CLIENT))
  {
    ret_desc->buffer[pos]=TYPE_IP;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=LENGTH_IP;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->ncp.n_ip >> 24);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->ncp.n_ip >> 16) & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->ncp.n_ip >>  8) & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->ncp.n_ip & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
  }
      /*
       * Gateway Address (only server mode)
       */
  if(((ppp_data->ncp.s_rejected & (1UL << MASK_TYPE_IP)) EQ 0) &&
     (ppp_data->mode EQ PPP_SERVER)                            &&
     (ppp_data->ncp.n_gateway NEQ PPP_GATEWAY_DEFAULT))
  {
    ret_desc->buffer[pos]=TYPE_IP;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=LENGTH_IP;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->ncp.n_gateway >> 24);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->ncp.n_gateway >> 16) & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->ncp.n_gateway >>  8) & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->ncp.n_gateway & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
  }
      /*
       * Primary DNS address (only client mode)
       */
  if(((ppp_data->ncp.s_rejected & (1UL << MASK_TYPE_PDNS)) EQ 0) &&
     (ppp_data->mode EQ PPP_CLIENT))
  {
    ret_desc->buffer[pos]=TYPE_PDNS;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=LENGTH_PDNS;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->ncp.n_pdns >> 24);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->ncp.n_pdns >> 16) & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->ncp.n_pdns >>  8) & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->ncp.n_pdns & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
  }
      /*
       * Secondary DNS address (only client mode)
       */
  if(((ppp_data->ncp.s_rejected & (1UL << MASK_TYPE_SDNS)) EQ 0) &&
     (ppp_data->mode EQ PPP_CLIENT))
  {
    ret_desc->buffer[pos]=TYPE_SDNS;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=LENGTH_SDNS;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->ncp.n_sdns >> 24);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->ncp.n_sdns >> 16) & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)((ppp_data->ncp.n_sdns >>  8) & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
    ret_desc->buffer[pos]=(UBYTE)(ppp_data->ncp.n_sdns & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    pos++;
  }
  /*
   * insert packet length
   */
  ret_desc->len=pos;
  ret_desc->buffer[len_pos]=(UBYTE)(pos >> 8);/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  len_pos++;
  ret_desc->buffer[len_pos]=(UBYTE)(pos & 0x00ff);/*lint !e415 !e416 creation and access of out-of-bounds pointer */

  /*
   * return the created packet
   */
  ppp_data->ncp.scr=TRUE;
  *ptr_packet=ret_desc;

} /* ncp_get_scr() */



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

  TRACE_FUNCTION( "ncp_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 + NCP_TERM_REQ_LENGTH));
  /*
   * fill the packet
   */
  ret_desc->next = (ULONG)NULL;
  ret_desc->len  = NCP_TERM_REQ_LENGTH;
  pos            = 0;
    /*
     * Code field
     */
  ret_desc->buffer[pos] = CODE_TERM_REQ;
  pos++;
    /*
     * Identifier field
     */
  ret_desc->buffer[pos] = ppp_data->ncp.nstri;/*lint !e415 access of out-of-bounds pointer */
  pos++;
    /*
     * Length field
     */
  ret_desc->buffer[pos] = 0;/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  pos++;
  ret_desc->buffer[pos] = NCP_TERM_REQ_LENGTH;/*lint !e415 !e416 creation and access 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 creation and access of out-of-bounds pointer */
  pos++;
  ret_desc->buffer[pos] = (U8)((ppp_data->ppp_cause)      & 0x00ff);/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  pos++;

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



/*
+------------------------------------------------------------------------------
| Function    : ncp_analyze_first_ipcp
+------------------------------------------------------------------------------
| Description : The function ncp_analyze_first_ipcp() determine whether the
|               given packet is a Configure Request packet. If so the function
|               analyzes the packet, sets some values in the data structure and
|               returns the values for header comression.
|
| Parameters  : packet     - received packet
|               ptr_result - returns the result of the analysis
|               ptr_hc     - returns requested header compression
|               ptr_msid   - returns requested max slot identifier
|
+------------------------------------------------------------------------------
*/
GLOBAL void ncp_analyze_first_ipcp(T_desc2* packet,
                                   UBYTE*   ptr_result,
                                   UBYTE*   ptr_hc,
                                   UBYTE*   ptr_msid)
{
  USHORT  packet_len;
  UBYTE   type_len;
  USHORT  pos;
  USHORT  analyzed;
  USHORT  protocol_hc;
  ULONG   ip;
  ULONG   pdns;
  ULONG   sdns;

  TRACE_FUNCTION( "ncp_analyze_first_ipcp" );

  /*
   * check whether it is a Configure Request packet and
   * for correct length field
   */
  packet_len = packet->buffer[2];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  packet_len <<= 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  if((packet->buffer[0] NEQ CODE_CONF_REQ) ||
     (packet_len > packet->len) ||
     (packet_len < 4))
  {
    *ptr_result = FALSE;
    return;
  }
  /*
   * check consistence of length of packet and length of configuration options
   */
  pos=5;
  while(pos < packet_len)
  {
    if(packet->buffer[pos] < 2)/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    {
      *ptr_result = FALSE;
      return;
    }
    pos+= packet->buffer[pos];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
  }
  if((pos - 1) NEQ packet_len)
  {
    *ptr_result = FALSE;
    return;
  }
  /*
   * analyze configuration options
   */
  ppp_data->ncp.r_hc   = PPP_HC_DEFAULT;
  ppp_data->ncp.r_msid = PPP_MSID_DEFAULT;
  ppp_data->ncp.n_ip   = PPP_IP_DEFAULT;
  ppp_data->ncp.n_pdns = PPP_PDNS_DEFAULT;
  ppp_data->ncp.n_sdns = PPP_SDNS_DEFAULT;
  pos=4;
    /*
     * 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 !e662 !e661 possible creation and access of out-of-bounds pointer*/
    switch(packet->buffer[pos])/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    {
      /*
       * yet supported configuration options
       */
      case TYPE_HC: /* Header Compression */
        protocol_hc = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        protocol_hc <<= 8;
        protocol_hc+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        if((analyzed & (1UL << MASK_TYPE_HC)) EQ 0)
        {
          analyzed|= (1UL << MASK_TYPE_HC);
          /*
           * max slot identifier should be between 3 and 254
           * comp slot identifier may be compressed
           */
          if((protocol_hc EQ DTI_PID_CTCP) &&
             (packet->buffer[pos + 4] >= 3) &&
             (packet->buffer[pos + 5] EQ PPP_CSID_YES))/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
          {
            ppp_data->ncp.r_hc   = PPP_HC_VJ;
            ppp_data->ncp.r_msid = packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
            if(ppp_data->ncp.r_msid > 254)
              ppp_data->ncp.r_msid = 254;
          }
        }
        break;
      case TYPE_IP:
        ip = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        ip = (ip << 8);
        ip+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        ip = (ip << 8);
        ip+= packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        ip = (ip << 8);
        ip+= packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        if((analyzed & (1UL << MASK_TYPE_IP)) EQ 0)
        {
          analyzed|=(1UL << MASK_TYPE_IP);
          ppp_data->ncp.n_ip = ip;
        }
        break;
      case TYPE_PDNS:
        pdns = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        pdns = (pdns << 8);
        pdns+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        pdns = (pdns << 8);
        pdns+= packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        pdns = (pdns << 8);
        pdns+= packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        if((analyzed & (1UL << MASK_TYPE_PDNS)) EQ 0)
        {
          analyzed|=(1UL << MASK_TYPE_PDNS);
          ppp_data->ncp.n_pdns = pdns;
        }
        break;
      case TYPE_SDNS:
        sdns = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        sdns = (sdns << 8);
        sdns+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        sdns = (sdns << 8);
        sdns+= packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        sdns = (sdns << 8);
        sdns+= packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        if((analyzed & (1UL << MASK_TYPE_SDNS)) EQ 0)
        {
          analyzed|=(1UL << MASK_TYPE_SDNS);
          ppp_data->ncp.n_sdns = sdns;
        }
        break;
      default:
        /*
         * not supported configuration options are not analysed
         */
        break;
    }
    pos+= type_len;
  }
  /*
   * all configuration options analyzed
   */
  *ptr_hc     = ppp_data->ncp.r_hc;
  *ptr_msid   = ppp_data->ncp.r_msid;
  *ptr_result = TRUE;
} /* ncp_analyze_first_ipcp() */



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

  TRACE_FUNCTION( "ncp_fill_out_packet" );

  if((ppp_data->pco_mask & PPP_PCO_MASK_IPCP_HC)   ||
     (ppp_data->pco_mask & PPP_PCO_MASK_IPCP_IP)   ||
     (ppp_data->pco_mask & PPP_PCO_MASK_IPCP_PDNS) ||
     (ppp_data->pco_mask & PPP_PCO_MASK_IPCP_SDNS))
  {
    pos=*ptr_pos;
    /*
     * create the Configure-Request packet
     */
      /*
       * Protocol ID
       */
    pco_buf[pos] = PROTOCOL_IPCP_MSB;
    pos++;
    pco_buf[pos] = PROTOCOL_IPCP_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_IPCP_HC)
    {
            /*
             * Header Compression
             */
      if(ppp_data->ncp.r_hc EQ PPP_HC_VJ)
      {
        pco_buf[pos] = TYPE_HC;
        pos++;
        pco_buf[pos] = LENGTH_HC_VJ;
        pos++;
        pco_buf[pos] = PROTOCOL_VJ_MSB;
        pos++;
        pco_buf[pos] = PROTOCOL_VJ_LSB;
        pos++;
        pco_buf[pos] = ppp_data->ncp.r_msid;
        pos++;
        pco_buf[pos] = PPP_CSID_YES;
        pos++;
      }
    }

    if(ppp_data->pco_mask & PPP_PCO_MASK_IPCP_IP)
    {
            /*
             * IP Address
             */
      pco_buf[pos] = TYPE_IP;
      pos++;
      pco_buf[pos] = LENGTH_IP;
      pos++;
      pco_buf[pos] = (UBYTE)(ppp_data->ncp.n_ip >> 24);
      pos++;
      pco_buf[pos] = (UBYTE)((ppp_data->ncp.n_ip >> 16) & 0x000000ff);
      pos++;
      pco_buf[pos] = (UBYTE)((ppp_data->ncp.n_ip >> 8) & 0x000000ff);
      pos++;
      pco_buf[pos] = (UBYTE)(ppp_data->ncp.n_ip & 0x000000ff);
      pos++;
    }

    if(ppp_data->pco_mask & PPP_PCO_MASK_IPCP_PDNS)
    {
            /*
             * primary DNS Address
             */
      pco_buf[pos] = TYPE_PDNS;
      pos++;
      pco_buf[pos] = LENGTH_PDNS;
      pos++;
      pco_buf[pos] = (UBYTE)(ppp_data->ncp.n_pdns >> 24);
      pos++;
      pco_buf[pos] = (UBYTE)((ppp_data->ncp.n_pdns >> 16) & 0x000000ff);
      pos++;
      pco_buf[pos] = (UBYTE)((ppp_data->ncp.n_pdns >> 8) & 0x000000ff);
      pos++;
      pco_buf[pos] = (UBYTE)(ppp_data->ncp.n_pdns & 0x000000ff);
      pos++;
    }

    if(ppp_data->pco_mask & PPP_PCO_MASK_IPCP_SDNS)
    {
            /*
             * secondary DNS Address
             */
      pco_buf[pos] = TYPE_SDNS;
      pos++;
      pco_buf[pos] = LENGTH_SDNS;
      pos++;
      pco_buf[pos] = (UBYTE)(ppp_data->ncp.n_sdns >> 24);
      pos++;
      pco_buf[pos] = (UBYTE)((ppp_data->ncp.n_sdns >> 16) & 0x000000ff);
      pos++;
      pco_buf[pos] = (UBYTE)((ppp_data->ncp.n_sdns >> 8) & 0x000000ff);
      pos++;
      pco_buf[pos] = (UBYTE)(ppp_data->ncp.n_sdns & 0x000000ff);
      pos++;
    }

        /*
         * insert packet length
         */
    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];

    /*
     * return new position
     */
    *ptr_pos=pos;
  }

  if(ppp_data->pco_mask & PPP_PCO_MASK_IPCP_GATEWAY)
  {
    pos=*ptr_pos;
    /*
     * create the Configure-NAK packet
     */
      /*
       * Protocol ID
       */
    pco_buf[pos] = PROTOCOL_IPCP_MSB;
    pos++;
    pco_buf[pos] = PROTOCOL_IPCP_LSB;
    pos++;
      /*
       * Length of Protocol contents (store the position)
       */
    len_pos1 = pos;
    pos++;
        /*
         * Code field
         */
    pco_buf[pos] = CODE_CONF_NAK;
    pos++;
        /*
         * Identifier field (some value)
         */
    pco_buf[pos] = 1;
    pos++;
        /*
         * Length field (store the position)
         */
    len_pos2 = pos;
    pos++;
    pos++;

          /*
           * dynamic Gateway Address
           */
    pco_buf[pos] = TYPE_IP;
    pos++;
    pco_buf[pos] = LENGTH_IP;
    pos++;
    pco_buf[pos] = 0;
    pos++;
    pco_buf[pos] = 0;
    pos++;
    pco_buf[pos] = 0;
    pos++;
    pco_buf[pos] = 0;
    pos++;

        /*
         * insert packet length
         */
    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];

    /*
     * return new position
     */
    *ptr_pos=pos;
  }
} /* ncp_fill_out_packet() */



/*
+------------------------------------------------------------------------------
| Function    : ncp_analyze_pco
+------------------------------------------------------------------------------
| Description : The function ncp_analyze_pco() analyzes the return packet from
|               PDP activation and determines the primary and secondary DNS
|               address and the Gateway address.
|
| Parameters  : pco_buf     - pointer to the protocol configuration options
|               pos         - position where the IPCP packet starts
|               ptr_dns1    - returns primary DNS address
|               ptr_dns2    - returns secondary DNS address
|               ptr_gateway - returns Gateway address
|
+------------------------------------------------------------------------------
*/
GLOBAL void ncp_analyze_pco (UBYTE pco_buf[],
                             USHORT pos,
                             ULONG* ptr_dns1,
                             ULONG* ptr_dns2,
                             ULONG* ptr_gateway)
{
  USHORT  packet_len;
  USHORT  start_pos;
  UBYTE   type_len;
  USHORT  analyzed;
  ULONG   pdns;
  ULONG   sdns;
  ULONG   gateway;

  TRACE_FUNCTION( "ncp_analyze_pco" );

  /*
   * check for correct length field
   */
  pos+= 2;
  packet_len = pco_buf[pos + 3];
  packet_len <<= 8;
  packet_len+= pco_buf[pos + 4];
  if(packet_len NEQ pco_buf[pos])
    return;
  pos++;
  /*
   * check of code field
   */
  if((pco_buf[pos] NEQ CODE_CONF_REQ) &&
     (pco_buf[pos] NEQ CODE_CONF_NAK) &&
     (pco_buf[pos] NEQ CODE_CONF_ACK))
    return;
  /*
   * analyze configuration options
   */
  start_pos = pos;
  pos+= 4;
    /*
     * analyzed is a bit field and marks all already analyzed
     * configuration options in order to determine configuration options
     * which are listed more than once
     */
  analyzed=0;
  while((pos - start_pos) < packet_len)
  {
    type_len=pco_buf[pos + 1];
    switch(pco_buf[pos])
    {
      /*
       * search for IP configuration option
       */
      case TYPE_IP:
        gateway = pco_buf[pos + 2];
        gateway = (gateway << 8);
        gateway+= pco_buf[pos + 3];
        gateway = (gateway << 8);
        gateway+= pco_buf[pos + 4];
        gateway = (gateway << 8);
        gateway+= pco_buf[pos + 5];
        if(((analyzed & (1UL << MASK_TYPE_IP)) EQ 0) &&
           (*ptr_gateway EQ PPP_GATEWAY_DEFAULT)     &&
           (pco_buf[start_pos] EQ CODE_CONF_REQ))
        {
          analyzed|=(1UL << MASK_TYPE_IP);
          *ptr_gateway = gateway;
        }
        break;

      /*
       * search for DNS configuration options
       */
      case TYPE_PDNS:
        pdns = pco_buf[pos + 2];
        pdns = (pdns << 8);
        pdns+= pco_buf[pos + 3];
        pdns = (pdns << 8);
        pdns+= pco_buf[pos + 4];
        pdns = (pdns << 8);
        pdns+= pco_buf[pos + 5];
        if(((analyzed & (1UL << MASK_TYPE_PDNS)) EQ 0) &&
           (*ptr_dns1 EQ PPP_PDNS_DEFAULT)             &&
           ((pco_buf[start_pos] EQ CODE_CONF_NAK) ||
            (pco_buf[start_pos] EQ CODE_CONF_ACK)))
        {
          analyzed|=(1UL << MASK_TYPE_PDNS);
          *ptr_dns1 = pdns;
        }
        break;

      case TYPE_SDNS:
        sdns = pco_buf[pos + 2];
        sdns = (sdns << 8);
        sdns+= pco_buf[pos + 3];
        sdns = (sdns << 8);
        sdns+= pco_buf[pos + 4];
        sdns = (sdns << 8);
        sdns+= pco_buf[pos + 5];
        if(((analyzed & (1UL << MASK_TYPE_SDNS)) EQ 0) &&
           (*ptr_dns2 EQ PPP_SDNS_DEFAULT)             &&
           ((pco_buf[start_pos] EQ CODE_CONF_NAK) ||
            (pco_buf[start_pos] EQ CODE_CONF_ACK)))
        {
          analyzed|=(1UL << MASK_TYPE_SDNS);
          *ptr_dns2 = sdns;
        }
        break;
      default:
        /*
         * other configuration options are not analysed
         */
        break;
    }
    pos+= type_len;
  }
} /* ncp_analyze_pco() */



/*
+------------------------------------------------------------------------------
| Function    : ncp_rcr
+------------------------------------------------------------------------------
| Description : The function ncp_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 ncp_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;
  UBYTE    error_found;
  USHORT   protocol_hc;
  UBYTE    csid;
  ULONG    ip;
  ULONG    pdns;
  ULONG    sdns;

  TRACE_FUNCTION( "ncp_rcr" );

  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  packet_len <<= 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 creation and access 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)/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    {
      *forward=FORWARD_DISCARD;
      return;
    }
    pos += packet->buffer[pos];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
  }
  if((pos - 1) NEQ packet_len)
  {
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * check whether it is a new identifier
   */
  *isnew=TRUE;
  if((ppp_data->ncp.rcr) && (ppp_data->ncp.lrcri EQ packet->buffer[1]))/*lint !e415 access of out-of-bounds pointer */
    *isnew=FALSE;
  ppp_data->ncp.lrcri=packet->buffer[1];/*lint !e415 access of out-of-bounds pointer */
  ppp_data->ncp.rcr=TRUE;
  /*
   * analyze configuration options
   */
  ppp_data->ncp.r_hc   = PPP_HC_DEFAULT;
  ppp_data->ncp.r_msid = PPP_MSID_DEFAULT;
  csid                 = 0;
  if(ppp_data->mode EQ PPP_SERVER)
  {
    ppp_data->ncp.n_ip   = PPP_IP_DEFAULT;
    ppp_data->ncp.n_pdns = PPP_PDNS_DEFAULT;
    ppp_data->ncp.n_sdns = PPP_SDNS_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 !e662 !e661 possible creation and access of out-of-bounds pointer*/
    switch(packet->buffer[pos])/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    {
      /*
       * yet supported configuration options
       */
      case TYPE_HC: /* Header Compression */
        protocol_hc = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        protocol_hc <<= 8;
        protocol_hc+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        if(protocol_hc EQ DTI_PID_CTCP)
        {
          ppp_data->ncp.r_hc   = PPP_HC_VJ;
          ppp_data->ncp.r_msid = packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
          csid                 = packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        }

        switch(code_ret)
        {
          case CODE_CONF_ACK:
            if(((analyzed & (1UL << MASK_TYPE_HC)) EQ 0) &&
               (ppp_data->ncp.r_hc EQ ppp_data->ncp.req_hc))
            {
              if((ppp_data->ncp.r_hc EQ PPP_HC_VJ) &&
                 (type_len EQ LENGTH_HC_VJ))
              {
                if((ppp_data->mode EQ PPP_SERVER) &&
                   (ppp_data->ncp.r_msid >= ppp_data->ncp.s_msid) &&
                   (csid EQ PPP_CSID_YES) &&
                   (ppp_data->ncp.s_hc EQ PPP_HC_VJ))
                {
                  analyzed|=(1UL << MASK_TYPE_HC);
                  pos+= LENGTH_HC_VJ;
                  break;
                }
                /*
                 * include here negotiation in client mode
                 */
              }
              /*
               * include here additional header compression protocols
               */
            }
            code_ret=CODE_CONF_NAK;
            /* fall through */
          case CODE_CONF_NAK:
            /*
             * this configuration option will NAKed only if the compression
             * protocol is not Van Jacobson Header Compression
             */
            if(((analyzed & (1UL << MASK_TYPE_HC)) EQ 0) &&
               (ppp_data->ncp.req_hc NEQ PPP_HC_DEFAULT) &&
               (ppp_data->ncp.s_hc EQ PPP_HC_VJ) &&
               ((protocol_hc NEQ DTI_PID_CTCP) ||
                (type_len NEQ LENGTH_HC_VJ) ||
                ((ppp_data->ncp.r_msid >= ppp_data->ncp.s_msid) &&
                 (csid EQ PPP_CSID_YES))))
            {
              analyzed|= (1UL << MASK_TYPE_HC);

              error_found = FALSE;
              /*
               * this implementation is only for server mode
               */
              if(type_len < LENGTH_HC_VJ)
              {
                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_HC_VJ
                                                           - type_len));
                temp_desc->next = packet->next;
                temp_desc->len  = packet_len + LENGTH_HC_VJ - type_len;
                memcpy(temp_desc->buffer, packet->buffer, pos);/*lint !e669 !e670 possible data overrun*/
                memcpy(&temp_desc->buffer[pos + LENGTH_HC_VJ - type_len],
                       &packet->buffer[pos],
                       packet_len - pos);/*lint !e662 !e669 !e670 possible creation of out-of-bounds pointer*/
                arb_discard_packet(packet);
                packet_len+= (LENGTH_HC_VJ - type_len);
                pos       += (LENGTH_HC_VJ - type_len);
                packet     = temp_desc;

                error_found = TRUE;
              }
              else if(ppp_data->ncp.r_hc NEQ PPP_HC_VJ)
              {
                error_found = TRUE;
              }
              else if(type_len > LENGTH_HC_VJ)
              {
                error_found = TRUE;
              }
              if(error_found EQ TRUE)
              {
                packet->buffer[copy_pos] = TYPE_HC;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos] = LENGTH_HC_VJ;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos] = PROTOCOL_VJ_MSB;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos] = PROTOCOL_VJ_LSB;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos] = ppp_data->ncp.req_msid;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos] = PPP_CSID_YES;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
              }
              pos+= type_len;
              break;
            }
            code_ret = CODE_CONF_REJ;
            copy_pos = 4;
            /* fall through */
          case CODE_CONF_REJ:
            if(((analyzed & (1UL << MASK_TYPE_HC)) EQ 0) &&
               (ppp_data->ncp.req_hc NEQ PPP_HC_DEFAULT) &&
               (ppp_data->ncp.s_hc EQ PPP_HC_VJ) &&
               ((ppp_data->ncp.s_rejected & (1UL << MASK_TYPE_HC)) EQ 0) &&
               ((protocol_hc NEQ DTI_PID_CTCP) ||
                (type_len NEQ LENGTH_HC_VJ) ||
                ((ppp_data->ncp.r_msid >= ppp_data->ncp.s_msid) &&
                 (csid EQ PPP_CSID_YES))))
            {
              analyzed|= (1UL << MASK_TYPE_HC);
              pos+= type_len;
              break;
            }
            /*
             * set s_hc to default because we reject this configuration option
             */
            ppp_data->ncp.s_hc = PPP_HC_DEFAULT;
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
          default:
            TRACE_ERROR("Packet return code invalid");
            break;
        }
        break;
      case TYPE_IP:
        ip = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        ip = (ip << 8);
        ip+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        ip = (ip << 8);
        ip+= packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        ip = (ip << 8);
        ip+= packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/

        switch(code_ret)
        {
          case CODE_CONF_ACK:
            if(((analyzed & (1UL << MASK_TYPE_IP)) EQ 0) &&
               (type_len EQ LENGTH_IP))
            {
              if((ppp_data->mode EQ PPP_SERVER) &&
                 (((ip EQ ppp_data->ncp.req_ip) &&
                   (ppp_data->ncp.req_ip NEQ PPP_IP_DEFAULT)) ||
                  ((ip NEQ PPP_IP_DEFAULT) &&
                   (ppp_data->ncp.req_ip EQ PPP_IP_DEFAULT))))
              {
                analyzed|=(1UL << MASK_TYPE_IP);
                ppp_data->ncp.n_ip = ip;
                pos+=LENGTH_IP;
                break;
              }
              else if((ppp_data->mode EQ PPP_CLIENT) &&
                      (ip NEQ PPP_IP_DEFAULT))
              {
                /*
                 * accept Gateway address
                 */
                analyzed|=(1UL << MASK_TYPE_IP);
                ppp_data->ncp.n_gateway = ip;
                pos+=LENGTH_IP;
                break;
              }
            }
            code_ret=CODE_CONF_NAK;
            /* fall through */
          case CODE_CONF_NAK:
            /*
             * this option will be rejected in following cases:
             * - occurence more than once
             * - in client mode if received IP is dynamic
             * - in server mode if received and requested IP are dynamic
             */
            if(((analyzed & (1UL << MASK_TYPE_IP)) EQ 0) &&
               (((ppp_data->mode EQ PPP_SERVER) &&
                 ((ip NEQ ppp_data->ncp.req_ip) ||
                  (ppp_data->ncp.req_ip NEQ PPP_IP_DEFAULT))) ||
                ((ppp_data->mode EQ PPP_CLIENT) &&
                 (ip NEQ PPP_IP_DEFAULT))))
            {
              analyzed|=(1UL << MASK_TYPE_IP);

              error_found=FALSE;
              if(type_len < LENGTH_IP)
              {
                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_IP
                                                           - type_len));
                temp_desc->next = packet->next;
                temp_desc->len  = packet_len + LENGTH_IP - type_len;
                memcpy(temp_desc->buffer, packet->buffer, pos);/*lint !e669 !e670 Possible data overrun*/
                memcpy(&temp_desc->buffer[pos + LENGTH_IP - type_len],
                       &packet->buffer[pos],
                       packet_len - pos);/*lint !e662 !e669 !e670 possible creation of out-of-bounds pointer*/
                arb_discard_packet(packet);
                packet_len += (LENGTH_IP - type_len);
                pos        += (LENGTH_IP - type_len);
                packet      = temp_desc;
                error_found = TRUE;
              }
              else if((ip NEQ ppp_data->ncp.req_ip) &&
                      (ppp_data->ncp.req_ip NEQ PPP_IP_DEFAULT) &&
                      (ppp_data->mode EQ PPP_SERVER))
              {
                error_found=TRUE;
              }
              else if(type_len > LENGTH_IP)
              {
                error_found=TRUE;
              }
              if(error_found EQ TRUE)
              {
                packet->buffer[copy_pos]=TYPE_IP;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=LENGTH_IP;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)(ppp_data->ncp.req_ip >> 24);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)((ppp_data->ncp.req_ip >> 16)
                                                 & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)((ppp_data->ncp.req_ip >>  8)
                                                 & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)(ppp_data->ncp.req_ip
                                                 & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
              }
              pos+= type_len;
              break;
            }
            code_ret = CODE_CONF_REJ;
            copy_pos = 4;
            /* fall through */
          case CODE_CONF_REJ:
            if(((analyzed & (1UL << MASK_TYPE_IP)) EQ 0) &&
               (((ppp_data->mode EQ PPP_SERVER) &&
                 ((ip NEQ ppp_data->ncp.req_ip) ||
                  (ppp_data->ncp.req_ip NEQ PPP_IP_DEFAULT))) ||
                ((ppp_data->mode EQ PPP_CLIENT) &&
                 (ip NEQ PPP_IP_DEFAULT))))
            {
              analyzed|=(1UL << MASK_TYPE_IP);
              pos+=type_len;
              break;
            }
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
          default:
            TRACE_ERROR("Packet return code invalid");
            break;
        }
        break;
      case TYPE_PDNS:  /* only in server mode allowed */
        pdns = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        pdns = (pdns << 8);
        pdns+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        pdns = (pdns << 8);
        pdns+= packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        pdns = (pdns << 8);
        pdns+= packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/

        switch(code_ret)
        {
          case CODE_CONF_ACK:
            if(((analyzed & (1UL << MASK_TYPE_PDNS)) EQ 0) &&
               (ppp_data->mode EQ PPP_SERVER) &&
               (type_len EQ LENGTH_PDNS) &&
               (((pdns EQ ppp_data->ncp.req_pdns) &&
                 (ppp_data->ncp.req_pdns NEQ PPP_PDNS_DEFAULT)) ||
                ((pdns NEQ PPP_PDNS_DEFAULT) &&
                 (ppp_data->ncp.req_pdns EQ PPP_PDNS_DEFAULT))))
            {
              analyzed|=(1UL << MASK_TYPE_PDNS);
              ppp_data->ncp.n_pdns = pdns;
              pos+= LENGTH_PDNS;
              break;
            }
            code_ret=CODE_CONF_NAK;
            /* fall through */
          case CODE_CONF_NAK:
            /*
             * this option will be rejected in following cases:
             * - occurence more than once
             * - client mode
             * - received and requested PDNS are dynamic
             */
            if(((analyzed & (1UL << MASK_TYPE_PDNS)) EQ 0) &&
               (ppp_data->mode EQ PPP_SERVER) &&
               ((pdns NEQ ppp_data->ncp.req_pdns) ||
                (ppp_data->ncp.req_pdns NEQ PPP_PDNS_DEFAULT)))
            {
              analyzed|=(1UL << MASK_TYPE_PDNS);

              error_found=FALSE;
              if(type_len < LENGTH_PDNS)
              {
                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_PDNS
                                                           - type_len));
                temp_desc->next = packet->next;
                temp_desc->len  = packet_len + LENGTH_PDNS - type_len;
                memcpy(temp_desc->buffer, packet->buffer, pos);/*lint !e669 !e670 Possible data overrun*/
                memcpy(&temp_desc->buffer[pos + LENGTH_PDNS - type_len],
                       &packet->buffer[pos],
                       packet_len - pos);/*lint !e662 !e669 !e670 possible creation of out-of-bounds pointer*/
                arb_discard_packet(packet);
                packet_len += (LENGTH_PDNS - type_len);
                pos        += (LENGTH_PDNS - type_len);
                packet      = temp_desc;
                error_found = TRUE;
              }
              else if((pdns NEQ ppp_data->ncp.req_pdns) &&
                      (ppp_data->ncp.req_pdns NEQ PPP_PDNS_DEFAULT))
              {
                error_found=TRUE;
              }
              else if(type_len > LENGTH_PDNS)
              {
                error_found=TRUE;
              }
              if(error_found EQ TRUE)
              {
                packet->buffer[copy_pos]=TYPE_PDNS;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=LENGTH_PDNS;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)(ppp_data->ncp.req_pdns >> 24);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)((ppp_data->ncp.req_pdns >> 16)
                                                 & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)((ppp_data->ncp.req_pdns >>  8)
                                                 & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)(ppp_data->ncp.req_pdns
                                                 & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
              }
              pos+= type_len;
              break;
            }
            code_ret = CODE_CONF_REJ;
            copy_pos = 4;
            /* fall through */
          case CODE_CONF_REJ:
            if(((analyzed & (1UL << MASK_TYPE_PDNS)) EQ 0) &&
               (ppp_data->mode EQ PPP_SERVER) &&
               ((pdns NEQ ppp_data->ncp.req_pdns) ||
                (ppp_data->ncp.req_pdns NEQ PPP_PDNS_DEFAULT)))
            {
              analyzed|=(1UL << MASK_TYPE_PDNS);
              pos+=type_len;
              break;
            }
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
          default:
            TRACE_ERROR("Packet return code invalid");
            break;
        }
        break;
      case TYPE_SDNS:  /* only in server mode allowed */
        sdns = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        sdns = (sdns << 8);
        sdns+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        sdns = (sdns << 8);
        sdns+= packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        sdns = (sdns << 8);
        sdns+= packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/

        switch(code_ret)
        {
          case CODE_CONF_ACK:
            if(((analyzed & (1UL << MASK_TYPE_SDNS)) EQ 0) &&
               (ppp_data->mode EQ PPP_SERVER) &&
               (type_len EQ LENGTH_SDNS) &&
               (((sdns EQ ppp_data->ncp.req_sdns) &&
                 (ppp_data->ncp.req_sdns NEQ PPP_SDNS_DEFAULT)) ||
                ((sdns NEQ PPP_SDNS_DEFAULT) &&
                 (ppp_data->ncp.req_sdns EQ PPP_SDNS_DEFAULT))))
            {
              analyzed|=(1UL << MASK_TYPE_SDNS);
              ppp_data->ncp.n_sdns = sdns;
              pos+= LENGTH_SDNS;
              break;
            }
            code_ret=CODE_CONF_NAK;
            /* fall through */
          case CODE_CONF_NAK:
            /*
             * this option will be rejected in following cases:
             * - occurence more than once
             * - client mode
             * - received and requested SDNS are dynamic
             */
            if(((analyzed & (1UL << MASK_TYPE_SDNS)) EQ 0) &&
               (ppp_data->mode EQ PPP_SERVER) &&
               ((sdns NEQ ppp_data->ncp.req_sdns) ||
                (ppp_data->ncp.req_sdns NEQ PPP_SDNS_DEFAULT)))
            {
              analyzed|=(1UL << MASK_TYPE_SDNS);

              error_found=FALSE;
              if(type_len < LENGTH_SDNS)
              {
                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_SDNS
                                                           - type_len));
                temp_desc->next = packet->next;
                temp_desc->len  = packet_len + LENGTH_SDNS - type_len;
                memcpy(temp_desc->buffer, packet->buffer, pos);/*lint !e669 !e670 Possible data overrun*/
                memcpy(&temp_desc->buffer[pos + LENGTH_SDNS - type_len],
                       &packet->buffer[pos],
                       packet_len - pos);/*lint !e662 !e669 !e670 possible creation  of out-of-bounds pointer*/
                arb_discard_packet(packet);
                packet_len += (LENGTH_SDNS - type_len);
                pos        += (LENGTH_SDNS - type_len);
                packet      = temp_desc;
                error_found = TRUE;
              }
              else if((sdns NEQ ppp_data->ncp.req_sdns) &&
                      (ppp_data->ncp.req_sdns NEQ PPP_SDNS_DEFAULT))
              {
                error_found=TRUE;
              }
              else if(type_len > LENGTH_SDNS)
              {
                error_found=TRUE;
              }
              if(error_found EQ TRUE)
              {
                packet->buffer[copy_pos]=TYPE_SDNS;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=LENGTH_SDNS;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)(ppp_data->ncp.req_sdns >> 24);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)((ppp_data->ncp.req_sdns >> 16)
                                                 & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)((ppp_data->ncp.req_sdns >>  8)
                                                 & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
                packet->buffer[copy_pos]=(UBYTE)(ppp_data->ncp.req_sdns
                                                 & 0x000000ff);/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
                copy_pos++;
              }
              pos+= type_len;
              break;
            }
            code_ret = CODE_CONF_REJ;
            copy_pos = 4;
            /* fall through */
          case CODE_CONF_REJ:
            if(((analyzed & (1UL << MASK_TYPE_SDNS)) EQ 0) &&
               (ppp_data->mode EQ PPP_SERVER) &&
               ((sdns NEQ ppp_data->ncp.req_sdns) ||
                (ppp_data->ncp.req_sdns NEQ PPP_SDNS_DEFAULT)))
            {
              analyzed|=(1UL << MASK_TYPE_SDNS);
              pos+=type_len;
              break;
            }
            while(type_len > 0)
            {
              packet->buffer[copy_pos]=packet->buffer[pos];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
          default:
            TRACE_ERROR("Packet return code invalid");
            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 !e662 !e661 possible creation and access of out-of-bounds pointer*/
              copy_pos++;
              pos++;
              type_len--;
            }
            break;
        }
    }
  }
  if(((analyzed & (1UL << MASK_TYPE_HC)) EQ 0) &&
     (ppp_data->ncp.s_hc EQ PPP_HC_VJ) &&
     (ppp_data->ncp.req_hc EQ PPP_HC_VJ) &&
     (code_ret NEQ CODE_CONF_REJ))
  {
    T_desc2* temp_desc;
    /*
     * add header compression to the configure Nak packet
     */
    code_ret = CODE_CONF_NAK;
    /*
     * 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_HC_VJ));
    temp_desc->next = packet->next;
    temp_desc->len  = packet_len + LENGTH_HC_VJ;
    memcpy(temp_desc->buffer, packet->buffer, copy_pos);/*lint !e669 !e670 Possible data overrun*/
    arb_discard_packet(packet);
    packet_len+= LENGTH_HC_VJ;
    packet     = temp_desc;
    /*
     * insert header compression option
     */
    packet->buffer[copy_pos] = TYPE_HC;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    copy_pos++;
    packet->buffer[copy_pos] = LENGTH_HC_VJ;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    copy_pos++;
    packet->buffer[copy_pos] = PROTOCOL_VJ_MSB;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    copy_pos++;
    packet->buffer[copy_pos] = PROTOCOL_VJ_LSB;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    copy_pos++;
    packet->buffer[copy_pos] = ppp_data->ncp.req_msid;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    copy_pos++;
    packet->buffer[copy_pos] = PPP_CSID_YES;/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    copy_pos++;
  }
  /*
   * 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 creation and access of out-of-bounds pointer */
    packet->buffer[3]=(UBYTE)(copy_pos & 0x00ff);/*lint !e415 !e416 creation and access of out-of-bounds pointer */
    return;
  }
  /*
   * all configuration options are acceptable
   */
  *forward=FORWARD_RCRP;
} /* ncp_rcr() */



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

  TRACE_FUNCTION( "ncp_rca" );

  packet_len = packet->buffer[2];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  packet_len <<= 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  if((packet_len < 4) ||
     (packet_len > packet->len) ||
     (ppp_data->ncp.scr EQ FALSE) ||
     (packet->buffer[1] NEQ ppp_data->ncp.nscri))/*lint !e415 access of out-of-bounds pointer */
  {
    /*
     * invalid packet
     */
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * acceptable packet
   */
  arb_discard_packet(packet);
  ppp_data->ncp.nscri++;
  *forward=FORWARD_RCA;
} /* ncp_rca() */



/*
+------------------------------------------------------------------------------
| Function    : ncp_rcn
+------------------------------------------------------------------------------
| Description : The function ncp_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 ncp_rcn (T_desc2** ptr_packet, UBYTE* forward)
{
  T_desc2* packet;
  USHORT   packet_len;
  UBYTE    type_len;
  USHORT   pos;
  USHORT   protocol_hc;
  ULONG    ip;
  ULONG    pdns;
  ULONG    sdns;

  TRACE_FUNCTION( "ncp_rcn" );

  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  packet_len <<= 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  if((packet_len > packet->len) ||
     (packet_len < 4) ||
     (ppp_data->ncp.scr EQ FALSE) ||
     (packet->buffer[1] NEQ ppp_data->ncp.nscri))/*lint !e415 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)/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    {
      *forward=FORWARD_DISCARD;
      return;
    }
    pos+= packet->buffer[pos];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
  }
  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 !e662 !e661 possible creation and access of out-of-bounds pointer*/
    switch(packet->buffer[pos])/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    {
      /*
       * yet supported configuration options
       */
      case TYPE_HC:
        protocol_hc = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        protocol_hc <<= 8;
        protocol_hc+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        if((protocol_hc EQ DTI_PID_CTCP) &&
           (ppp_data->ncp.req_hc EQ PPP_HC_VJ) &&
           (type_len EQ LENGTH_HC_VJ))
        {
          ppp_data->ncp.s_rejected &= ~(1UL << MASK_TYPE_HC);
          ppp_data->ncp.s_hc        = PPP_HC_VJ;
          ppp_data->ncp.s_msid      = ppp_data->ncp.req_msid;
        }
        break;
      case TYPE_IP:
        ip = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        ip = ip << 8;
        ip+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        ip = ip << 8;
        ip+= packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        ip = ip << 8;
        ip+= packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/

        if(type_len EQ LENGTH_IP)
        {
          ppp_data->ncp.s_rejected &= ~(1UL << MASK_TYPE_IP);
          if(ppp_data->mode EQ PPP_CLIENT)
            ppp_data->ncp.n_ip = ip;
          else if(ppp_data->ncp.req_gateway EQ PPP_GATEWAY_DEFAULT)
            ppp_data->ncp.n_gateway = ip;
        }
        break;
      case TYPE_PDNS:
        pdns = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        pdns = pdns << 8;
        pdns+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        pdns = pdns << 8;
        pdns+= packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        pdns = pdns << 8;
        pdns+= packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/

        if((type_len EQ LENGTH_PDNS) &&
           (ppp_data->mode EQ PPP_CLIENT))
        {
          ppp_data->ncp.s_rejected &= ~(1UL << MASK_TYPE_PDNS);
          ppp_data->ncp.n_pdns = pdns;
        }
        break;
      case TYPE_SDNS:
        sdns = packet->buffer[pos + 2];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        sdns = sdns << 8;
        sdns+= packet->buffer[pos + 3];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        sdns = sdns << 8;
        sdns+= packet->buffer[pos + 4];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
        sdns = sdns << 8;
        sdns+= packet->buffer[pos + 5];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/

        if((type_len EQ LENGTH_SDNS) &&
           (ppp_data->mode EQ PPP_CLIENT))
        {
          ppp_data->ncp.s_rejected &= ~(1UL << MASK_TYPE_SDNS);
          ppp_data->ncp.n_sdns = sdns;
        }
        break;
      default:
        /*
         * ignore unknown configuration options
         */
        break;
    }
    pos+= type_len;
  }
  /*
   * free this packet and create a new with changed configuration options
   */
  arb_discard_packet(packet);
  *forward=FORWARD_RCN;
  ppp_data->ncp.nscri++;
  ncp_get_scr(&packet);
  *ptr_packet=packet;
} /* ncp_rcn() */



/*
+------------------------------------------------------------------------------
| Function    : ncp_rcj
+------------------------------------------------------------------------------
| Description : The function ncp_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 ncp_rcj (T_desc2** ptr_packet, UBYTE* forward)
{
  T_desc2* packet;
  USHORT   packet_len;
  UBYTE    type_len;
  USHORT   pos;

  TRACE_FUNCTION( "ncp_rcj" );

  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  packet_len <<= 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  if((packet_len > packet->len) ||
     (packet_len < 4) ||
     (ppp_data->ncp.scr EQ FALSE) ||
     (packet->buffer[1] NEQ ppp_data->ncp.nscri))/*lint !e415 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)/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    {
      *forward=FORWARD_DISCARD;
      return;
    }
    pos+= packet->buffer[pos];/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
  }
  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 !e662 !e661 possible creation and access of out-of-bounds pointer*/
    switch(packet->buffer[pos])/*lint !e662 !e661 possible creation and access of out-of-bounds pointer*/
    {
      /*
       * yet supported configuration options
       */
      case TYPE_HC:
        ppp_data->ncp.s_rejected|= (1UL << MASK_TYPE_HC);
        ppp_data->ncp.s_hc = PPP_HC_DEFAULT;
        break;
      case TYPE_IP:
        if (ppp_data->mode EQ PPP_CLIENT)
        { /* error: server has to support valid IP address */
          *forward=FORWARD_DISCARD;
          return;
        }
        ppp_data->ncp.s_rejected |= (1UL << MASK_TYPE_IP);
        break;
      case TYPE_PDNS:
        ppp_data->ncp.s_rejected |= (1UL << MASK_TYPE_PDNS);
        break;
      case TYPE_SDNS:
        ppp_data->ncp.s_rejected |= (1UL << MASK_TYPE_SDNS);
        break;
      default:
        /*
         * ignore unknown configuration options
         */
        break;
    }
    pos+= type_len;
  }
  /*
   * free this packet and create a new with changed configuration options
   */
  arb_discard_packet(packet);
  *forward=FORWARD_RCN;
  ppp_data->ncp.nscri++;
  ncp_get_scr(&packet);
  *ptr_packet=packet;
} /* ncp_rcj() */



/*
+------------------------------------------------------------------------------
| Function    : ncp_rtr
+------------------------------------------------------------------------------
| Description : The function ncp_rtr() checks whether the given
|               Terminate Request packet is valid and if so it returns
|               FORWARD_RCA. Otherwise it returns FORWARD_DISCARD.
|
| Parameters  : ptr_packet - pointer to a Terminate Request packet
|               forward    - returns result of analysis
|
+------------------------------------------------------------------------------
*/
GLOBAL void ncp_rtr (T_desc2** ptr_packet, UBYTE* forward)
{
  T_desc2* packet;
  USHORT   packet_len;

  TRACE_FUNCTION( "ncp_rtr" );

  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  packet_len <<= 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 creation and access 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;
} /* ncp_rtr() */



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

  TRACE_FUNCTION( "ncp_rta" );

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

  if((ppp_data->ncp.str EQ TRUE) &&
     (packet->buffer[1] NEQ ppp_data->ncp.nstri))/*lint !e415 access of out-of-bounds pointer */
  {
    /*
     * invalid packet
     */
    *forward=FORWARD_DISCARD;
    return;
  }
  /*
   * acceptable packet
   */
  arb_discard_packet(packet);
  ppp_data->ncp.nstri++;
  *forward=FORWARD_RTA;
} /* ncp_rta() */



/*
+------------------------------------------------------------------------------
| Function    : ncp_rxj
+------------------------------------------------------------------------------
| Description : The function ncp_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 ncp_rxj (T_desc2** ptr_packet, UBYTE* forward)
{
  USHORT  packet_len;
  T_desc2* packet;

  TRACE_FUNCTION( "ncp_rxj" );

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

  switch(packet->buffer[4])/*lint !e415 !e416 creation and access 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:
      arb_discard_packet(packet);
      ncp_get_str(&packet);
      *ptr_packet = packet;
      *forward = FORWARD_RXJN;
      break;
    default:
      *forward=FORWARD_DISCARD;
      break;
  }
} /* ncp_rxj() */



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

  TRACE_FUNCTION( "ncp_ruc" );

  /*
   * check for correct length field
   */
  packet = *ptr_packet;
  packet_len = packet->buffer[2];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  packet_len <<= 8;
  packet_len+= packet->buffer[3];/*lint !e415 !e416 creation and access of out-of-bounds pointer */
  if((packet->len < packet_len) || (packet_len < 4))
  {
    *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 !e416 !e669 !e670 creation of out-of-bounds pointer */
  arb_discard_packet(packet);
  packet = temp_desc;

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

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

} /* ncp_ruc() */