0
mirror of https://github.com/Indemsys/Frequency_Inverter.git synced 2026-05-05 13:17:53 +00:00
Files
2022-01-04 12:22:53 +02:00

1465 lines
40 KiB
C

/**HEADER********************************************************************
*
* Copyright (c) 2008 Freescale Semiconductor;
* All Rights Reserved
*
* Copyright (c) 2004-2008 Embedded Access Inc.;
* All Rights Reserved
*
* Copyright (c) 1989-2008 ARC International;
* All Rights Reserved
*
***************************************************************************
*
* THIS SOFTWARE IS PROVIDED BY FREESCALE "AS IS" AND ANY EXPRESSED OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL FREESCALE OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
**************************************************************************
*
* $FileName: lcp.c$
* $Version : 3.8.10.0$
* $Date : Aug-27-2012$
*
* Comments:
*
* This file contains the implementation for the
* Link Control Protocol.
*
*END************************************************************************/
/*
** lcp.c - PPP Link Control Protocol.
**
** Copyright (c) 1989 Carnegie Mellon University.
** All rights reserved.
**
** Redistribution and use in source and binary forms are permitted
** provided that the above copyright notice and this paragraph are
** duplicated in all such forms and that any documentation,
** advertising materials, and other materials related to such
** distribution and use acknowledge that the software was developed
** by Carnegie Mellon University. The name of the
** University may not be used to endorse or promote products derived
** from this software without specific prior written permission.
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
** WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
/*
** Things to do:
**
** We need a way to let the application specify which configuration
** options to request (in order of preference), and which options to
** allow the peer (unordered set).
**
** Currently, the following are hard coded for both sides:
**
** MRU <= 1500 (1500 preferred, Receive side)
** MRU >= 68 (Send side)
** ACCM = _PPP_ACCM
** PFC = TRUE or FALSE (TRUE preferred)
** ACFC = TRUE or FALSE (TRUE preferred)
** FCS = CCITT-32, CCITT-16 or NULL
** (CCITT-16 preferred)
**
** The choice of authentication protocols depends on the
** existence of secrets. The following are supported
**
** AP = none or PAP
**
*/
#include <ppp.h>
#include "ppp_prv.h"
#if RTCSCFG_ENABLE_IP4
static boolean LCP_up(PPPFSM_CFG_PTR);
static void LCP_down(PPPFSM_CFG_PTR);
static void LCP_resetconfreq(PPPFSM_CFG_PTR);
static uint_32 LCP_buildconfreq(PPPFSM_CFG_PTR, uchar_ptr, uint_32);
static uint_32 LCP_recvconfreq(PPPFSM_CFG_PTR, boolean);
static boolean LCP_recvconfack(PPPFSM_CFG_PTR);
static boolean LCP_recvconfnak(PPPFSM_CFG_PTR);
static boolean LCP_recvconfrej(PPPFSM_CFG_PTR);
static boolean LCP_recvcoderej(PPPFSM_CFG_PTR);
static boolean LCP_recvextcode(PPPFSM_CFG_PTR);
static PPPFSM_CALL LCP_CALL = {
/* PROTOCOL */ PPP_PROT_LCP,
/* linkup() */ LCP_up,
/* linkdown() */ LCP_down,
/* resetreq() */ LCP_resetconfreq,
/* buildreq() */ LCP_buildconfreq,
/* recvreq() */ LCP_recvconfreq,
/* recvack() */ LCP_recvconfack,
/* recvnak() */ LCP_recvconfnak,
/* recvrej() */ LCP_recvconfrej,
/* testcode() */ LCP_recvcoderej,
/* recvcode() */ LCP_recvextcode
};
static LCP_NEG LCP_DEFAULT_NEG = {
/* NEG_* */ 0,1,0,0,0,1,1,0,
/* MRU */ DEFAULT_MRU,
/* ACCM */ 0xFFFFFFFFl,
/* AP */ 0
};
static LCP_NEG LCP_DEFAULT_NEG_PPPOE = {
/* NEG_* */ 1,0,0,0,0,0,0,0,
/* MRU */ 1492,
/* ACCM */ 0,
/* AP */ 0
};
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_init
* Returned Value : error code
* Comments :
* Called by PPP_init. Initializes the LCP Finite State Machine.
*
*END*-----------------------------------------------------------------*/
uint_32 LCP_init
(
_ppp_handle handle
/* [IN] - the PPP state structure */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
PPP_CFG_PTR ppp_ptr = handle;
ppp_ptr->LCP_STATE.DEVICE = ppp_ptr->DEVICE;
/* Start CR 2207 */
#if PPP_SECRETS_NOT_SHARED
ppp_ptr->LCP_STATE.HANDLE = handle;
#endif
/* End CR 2207 */
/* Initialize the FSM */
return PPPFSM_init(&ppp_ptr->LCP_FSM, handle, &LCP_CALL, &ppp_ptr->LCP_STATE);
#else
return RTCSERR_IP_IS_DISABLED;
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_destroy
* Returned Value : error code
* Comments :
* Called by PPP_init. Destroys the LCP Finite State Machine.
* Assumes the Finite State Machine has been initialized.
*
*END*-----------------------------------------------------------------*/
uint_32 LCP_destroy
(
_ppp_handle handle
/* [IN] - the PPP state structure */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
PPP_CFG_PTR ppp_ptr = handle;
/* Destroy the FSM */
return PPPFSM_destroy(&ppp_ptr->LCP_FSM);
#else
return RTCSERR_IP_IS_DISABLED;
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : PPP_lowerup
* Returned Value : void
* Comments :
* Called by application. Lower layer is up.
*
*END*-----------------------------------------------------------------*/
void PPP_lowerup
(
_ppp_handle handle
/* [IN] - the PPP state structure */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
PPP_CFG_PTR ppp_ptr = handle;
PPPFSM_lowerup(&ppp_ptr->LCP_FSM);
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : PPP_lowerdown
* Returned Value : void
* Comments :
* Called by application. Lower layer is down.
*
*END*-----------------------------------------------------------------*/
void PPP_lowerdown
(
_ppp_handle handle
/* [IN] - the PPP state structure */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
PPP_CFG_PTR ppp_ptr = handle;
PPPFSM_lowerdown(&ppp_ptr->LCP_FSM);
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : PPP_open
* Returned Value : error code
* Comments :
* Called by application. Begin negotiating PPP.
*
*END*-----------------------------------------------------------------*/
uint_32 PPP_open
(
_ppp_handle handle,
/* [IN] - the PPP state structure */
uint_32 options
/* [IN] - Startup options */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
PPP_CFG_PTR ppp_ptr = handle;
/* Do some error checking */
if (ppp_ptr->VALID != PPP_VALID) {
return RTCSERR_PPP_INVALID_HANDLE;
} /* Endif */
PPPFSM_open(&ppp_ptr->LCP_FSM, options);
return PPP_OK;
#else
return RTCSERR_IP_IS_DISABLED;
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : PPP_close
* Returned Value : error code
* Comments :
* Called by application. Begin closing PPP.
*
*END*-----------------------------------------------------------------*/
uint_32 PPP_close
(
_ppp_handle handle
/* [IN] - the PPP state structure */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
PPP_CFG_PTR ppp_ptr = handle;
/* Do some error checking */
if (ppp_ptr->VALID != PPP_VALID) {
return RTCSERR_PPP_INVALID_HANDLE;
} /* Endif */
PPPFSM_close(&ppp_ptr->LCP_FSM);
return PPP_OK;
#else
return RTCSERR_IP_IS_DISABLED;
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_recvextcode
* Returned Value : TRUE or FALSE
* Comments :
* Called by PPPFSM_Input. Parses an LCP packet with an extended
* code. Consumes fsm->PACKET if TRUE is returned.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean LCP_recvextcode
(
PPPFSM_CFG_PTR fsm
/* [IN] - State Machine */
)
{ /* Body */
PPP_CFG_PTR ppp_ptr = fsm->HANDLE;
LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
PPP_CALL_INTERNAL_PTR call_ptr = &ppp_ptr->LCP_CALL[PPP_CALL_ECHO_REPLY];
switch (fsm->CODE) {
case LCP_CODE_PROT_REJ:
lcp_ptr->ST_LCP_RX_REJECT++;
/*
** We should notify the rejected protocol, but there
** currently isn't any way to do this. What we'll do
** instead is to send a STOP message to the Tx task on
** behalf of the protocol.
**
** This will usually be sufficient, since the rejected
** protocol isn't likely to send another packet until
** either it receives a packet (in which case it's OK to
** reply) or the retransmission timer kicks in (which
** we're about to disable).
**
** Thus, this will effectively stop the rejected protocol.
*/
if (fsm->LENGTH >= 2) {
uint_16 protocol = ntohs(fsm->DATA);
PPP_send_stop(ppp_ptr, protocol);
} /* Endif */
PCB_free(fsm->PACKET);
break;
case LCP_CODE_ECHO_REQ:
lcp_ptr->ST_LCP_RX_ECHO++;
if (fsm->STATE < PPP_STATE_OPENED) {
PCB_free(fsm->PACKET);
} else {
htonc(fsm->DATA - CP_HDR_LEN, LCP_CODE_ECHO_REP);
htonl(fsm->DATA, 0); /* Set magic field to 0 */
lcp_ptr->ST_LCP_TX_REPLY++;
PPP_send_one(ppp_ptr, PPP_PROT_LCP, fsm->PACKET);
} /* Endif */
break;
case LCP_CODE_ECHO_REP:
lcp_ptr->ST_LCP_RX_REPLY++;
if (call_ptr->CALLBACK) {
call_ptr->CALLBACK(call_ptr->PARAM, fsm->ID, fsm->PACKET);
} /* Endif */
PCB_free(fsm->PACKET);
break;
case LCP_CODE_DISC_REQ:
lcp_ptr->ST_LCP_RX_DISCARD++;
PCB_free(fsm->PACKET);
break;
default:
return FALSE;
} /* Endswitch */
return TRUE;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_sendprotrej
* Returned Value : void
* Comments :
* Called by PPP_rx_task. Sends a ProtRej packet for some protocol.
* Consumes (sends) 'pcb'.
*
*END*-----------------------------------------------------------------*/
void LCP_sendprotrej
(
PCB_PTR pcb,
/* [IN] - packet to reject */
PPPFSM_CFG_PTR fsm
/* [IN/OUT] - State Machine */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
PPP_CFG_PTR ppp_ptr = fsm->HANDLE;
LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
uchar_ptr packet, src, dst;
uint_16 length;
uint_16 size = ppp_ptr->SEND_OPTIONS->MRU - CP_HDR_LEN;
length = pcb->FRAG[0].LENGTH;
packet = pcb->FRAG[0].FRAGMENT;
/* Truncate the packet if necessary */
if (length > size) {
length = size;
} /* Endif */
/* Make room for a Code-Reject header */
size = length + CP_HDR_LEN;
/* Copy the received packet (including protocol field) to the */
/* data portion of the Protocol-Reject */
src = packet + length;
dst = src + 2 + CP_HDR_LEN;
while (length--) *--dst = *--src;
/* Build a Code-Reject packet */
htons(packet, PPP_PROT_LCP); packet += 2;
*packet++ = LCP_CODE_PROT_REJ;
*packet++ = fsm->CURID;
fsm->CURID = (fsm->CURID + 1) & 0xFF;
htons(packet, size); packet += 2;
pcb->FRAG[0].LENGTH = size + 2;
lcp_ptr->ST_LCP_TX_REJECT++;
PPP_send_one(ppp_ptr, PPP_PROT_LCP, pcb);
#else
PCB_free(pcb);
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_resetconfreq
* Returned Value : void
* Comments :
* Called by PPPFSM_Sendconfreq when starting negotiation.
* Initializes the Send Options.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void LCP_resetconfreq
(
PPPFSM_CFG_PTR fsm
/* [IN] - State Machine */
)
{ /* Body */
LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
uint_32 if_type;
/* Start CR 2207 */
#if PPP_SECRETS_NOT_SHARED
PPP_CFG_PTR ppp_ptr = lcp_ptr->HANDLE;
#endif
/* End CR 2207 */
_iopcb_ioctl(lcp_ptr->DEVICE, IOPCB_IOCTL_GET_IFTYPE, &if_type);
if (if_type == IPIFTYPE_ETHERNET) {
lcp_ptr->SEND_OPT = PPP_DEFAULT_OPTIONS_PPPOE;
lcp_ptr->RECV_OPT = PPP_DEFAULT_OPTIONS_PPPOE;
lcp_ptr->RECV_NEG = LCP_DEFAULT_NEG_PPPOE;
} else {
lcp_ptr->SEND_OPT = PPP_DEFAULT_OPTIONS;
lcp_ptr->RECV_OPT = PPP_DEFAULT_OPTIONS;
lcp_ptr->RECV_NEG = LCP_DEFAULT_NEG;
lcp_ptr->RECV_NEG.ACCM = _PPP_ACCM;
} /* Endif */
/* Start CR 2207 */
if (PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS)) {
/* End CR 2207 */
lcp_ptr->RECV_NEG.NEG_AP = 1;
lcp_ptr->RECV_NEG.AP = PPP_PROT_CHAP;
/* Start CR 2207 */
} else if (PPP_SECRET(ppp_ptr,_PPP_PAP_RSECRETS)) {
/* End CR 2207 */
lcp_ptr->RECV_NEG.NEG_AP = 1;
lcp_ptr->RECV_NEG.AP = PPP_PROT_PAP;
} else {
lcp_ptr->RECV_NEG.NEG_AP = 0;
} /* Endif */
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_buildconfreq
* Returned Value : number of bytes written
* Comments :
* Called by PPPFSM_Sendconfreq. Builds a ConfReq packet.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static uint_32 LCP_buildconfreq
(
PPPFSM_CFG_PTR fsm,
/* [IN] - State Machine */
uchar_ptr outp,
/* [IN] - free packet */
uint_32 sizeleft
/* [IN] - size of packet */
)
{ /* Body */
LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
uint_32 totlen = 0;
uint_32 aplen;
#define LCP_BREQ(ci,len) \
*outp++ = LCP_CI_ ## ci; \
*outp++ = len; \
totlen += len
/*
** Generate configuration information for each option
** we want to negotiate.
*/
if (lcp_ptr->RECV_NEG.NEG_MRU) {
if (sizeleft >= totlen+4) {
LCP_BREQ(MRU,4);
htons(outp, lcp_ptr->RECV_NEG.MRU); outp += 2;
} /* Endif */
} /* Endif */
if (lcp_ptr->RECV_NEG.NEG_ACCM) {
if (sizeleft >= totlen+6) {
LCP_BREQ(ACCM,6);
htonl(outp, lcp_ptr->RECV_NEG.ACCM); outp += 4;
} /* Endif */
} /* Endif */
if (lcp_ptr->RECV_NEG.NEG_AP) {
switch (lcp_ptr->RECV_NEG.AP) {
case PPP_PROT_CHAP: aplen = 5; break;
default: aplen = 4; break;
} /* Endswitch */
if (sizeleft >= totlen+aplen) {
LCP_BREQ(AP,aplen);
htons(outp, lcp_ptr->RECV_NEG.AP); outp += 2;
switch (lcp_ptr->RECV_NEG.AP) {
case PPP_PROT_CHAP:
htonc(outp, 5); outp++; /* Only MD5 supported */
break;
} /* Endswitch */
} /* Endif */
} /* Endif */
if (lcp_ptr->RECV_NEG.NEG_PFC) {
if (sizeleft >= totlen+2) {
LCP_BREQ(PFC,2);
} /* Endif */
} /* Endif */
if (lcp_ptr->RECV_NEG.NEG_ACFC) {
if (sizeleft >= totlen+2) {
LCP_BREQ(ACFC,2);
} /* Endif */
} /* Endif */
return totlen;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_recvconfack
* Returned Value : TRUE or FALSE
* Comments :
* Called by PPPFSM_Recvconfack. Parses a ConfAck packet.
* This function should not modify any state if the ack is bad.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean LCP_recvconfack
(
PPPFSM_CFG_PTR fsm
/* [IN] - State Machine */
)
{ /* Body */
LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
uchar_ptr inp = fsm->DATA;
uint_32 sizeleft = fsm->LENGTH;
uint_32 aplen;
PPP_OPT ack_opt = lcp_ptr->RECV_OPT;
#define LCP_RACK(ci,len) \
if (sizeleft < len) goto badack; \
if (*inp++ != LCP_CI_ ## ci) goto badack; \
if (*inp++ != len) goto badack; \
sizeleft -= len
/*
** The ack must be identical to the last ConfReq we sent
*/
/*
** This situation can happend when size of data in our request packet is "0"
** So, size of received data in "ack" packet will be "0" too.
** As example: We send "REQ" packet with field PFC an ACFC "ON", modem send "NAK"
** for that field. We turn of that field, but we have not what negotiate else,
** so we send "REQ" packed,it looks like "7E FF 03 C0 21 01 6D 00 04 3F 15 7E"
** As you see size of data field is "0". But modem agree and send us "ACK" looks like
** "7E FF 03 C0 21 02 6D 00 04 F2 30 7E" and will be ready to start next stage of communication.
** In received packet from modem you can se size of data field is "0" too.
*/
if(sizeleft ==0)
{
return TRUE;
}
if (lcp_ptr->RECV_NEG.NEG_MRU) {
LCP_RACK(MRU,4);
ack_opt.MRU = ntohs(inp); inp += 2;
if (ack_opt.MRU != lcp_ptr->RECV_NEG.MRU) goto badack;
} /* Endif */
if (lcp_ptr->RECV_NEG.NEG_ACCM) {
LCP_RACK(ACCM,6);
ack_opt.ACCM = ntohl(inp); inp += 4;
if (ack_opt.ACCM != lcp_ptr->RECV_NEG.ACCM) goto badack;
} /* Endif */
if (lcp_ptr->RECV_NEG.NEG_AP) {
switch (lcp_ptr->RECV_NEG.AP) {
case PPP_PROT_CHAP: aplen = 5; break;
default: aplen = 4; break;
} /* Endswitch */
LCP_RACK(AP,aplen);
ack_opt.AP = ntohs(inp); inp += 2;
if (ack_opt.AP != lcp_ptr->RECV_NEG.AP) goto badack;
switch (ack_opt.AP) {
case PPP_PROT_CHAP:
if (ntohc(inp) != 5) goto badack; /* Only MD5 supported */
inp++;
ack_opt.AP_Start = CHAP_challenge;
break;
case PPP_PROT_PAP:
ack_opt.AP_Start = PAP_open;
break;
default:
ack_opt.AP = 0;
break;
} /* Endswitch */
} /* Endif */
if (lcp_ptr->RECV_NEG.NEG_PFC) {
LCP_RACK(PFC,2);
ack_opt.PFC = TRUE;
} /* Endif */
if (lcp_ptr->RECV_NEG.NEG_ACFC) {
LCP_RACK(ACFC,2);
ack_opt.ACFC = TRUE;
} /* Endif */
if (sizeleft) goto badack;
if (fsm->STATE < PPP_STATE_OPENED) {
lcp_ptr->RECV_OPT = ack_opt;
} /* Endif */
return TRUE;
badack:
return FALSE;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_recvconfnak
* Returned Value : TRUE or FALSE
* Comments :
* Called by PPPFSM_recvconfnak. Parses a ConfNak packet.
* This function should not modify any state if the nak is bad.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean LCP_recvconfnak
(
PPPFSM_CFG_PTR fsm
/* [IN] - State Machine */
)
{ /* Body */
LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
uchar_ptr inp = fsm->DATA;
uint_32 sizeleft = fsm->LENGTH;
LCP_NEG req_neg = lcp_ptr->RECV_NEG;
uchar code;
/* Start CR 2207 */
#if PPP_SECRETS_NOT_SHARED
PPP_CFG_PTR ppp_ptr = lcp_ptr->HANDLE;
#endif
/* End CR 2207 */
#define LCP_RNAK(len) \
if (sizeleft < len) goto badnak; \
if (*inp++ != len) goto badnak; \
sizeleft -= len
/*
** Nak'd codes must be in the same order as they were in the ConfReq
*/
code = *inp++;
if (sizeleft && req_neg.NEG_MRU && code == LCP_CI_MRU) {
LCP_RNAK(4);
/* We are prepared to accept maximum MRU of 1500 */
req_neg.MRU = ntohs(inp); inp += 2;
if (req_neg.MRU > DEFAULT_MRU) {
req_neg.MRU = DEFAULT_MRU;
} /* Endif */
code = *inp++;
} /* Endif */
if (sizeleft && req_neg.NEG_ACCM && code == LCP_CI_ACCM) {
LCP_RNAK(6);
/* Add any characters they want to our ACCM */
req_neg.ACCM |= ntohl(inp); inp += 4;
code = *inp++;
} /* Endif */
if (sizeleft && req_neg.NEG_AP && code == LCP_CI_AP) {
if (sizeleft < *inp || *inp < 4) goto badnak;
sizeleft -= *inp;
/*
** If AP is nak'd, we don't care what they want --
** we choose the next most desirable protocol. If there
** aren't any more to choose, we keep the last one we tried.
*/
inp += *inp - 1;
if (PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS)) {
req_neg.AP = PPP_PROT_CHAP;
} else {
switch (req_neg.AP) {
case PPP_PROT_CHAP:
/* CHAP was NAKed, try PAP */
if (PPP_SECRET(ppp_ptr,_PPP_PAP_RSECRETS)) {
req_neg.AP = PPP_PROT_PAP;
} /* Endif */
break;
case PPP_PROT_PAP:
/* no other authentication protocols known */
break;
default:
/* Unknown protocol NAKed, try CHAP */
if (PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS)) {
req_neg.AP = PPP_PROT_CHAP;
}
break;
} /* Endswitch */
}
code = *inp++;
} /* Endif */
/*
** If we advertised PFC and/or ACFC and the peer doesn't
** want it, they should send a ConfRej rather than a ConfNak,
** so we're not going to check for them here (if they are
** here, the switch statement below will catch it).
*/
#define LCP_RNAK_ADD(ci,len) \
if (req_neg.NEG_ ## ci || sizeleft < len || *inp++ != len) goto badnak; \
sizeleft -= len; \
req_neg.NEG_ ## ci = 1
/*
** There may be remaining codes if the peer wants us to
** negotiate an option we didn't include.
*/
while (sizeleft) {
switch (code) {
case LCP_CI_MRU:
LCP_RNAK_ADD(MRU,4);
req_neg.MRU = ntohs(inp); inp += 2;
if (req_neg.MRU > DEFAULT_MRU) {
req_neg.MRU = DEFAULT_MRU;
} /* Endif */
break;
case LCP_CI_ACCM:
LCP_RNAK_ADD(ACCM,6);
req_neg.ACCM |= ntohl(inp); inp += 4;
break;
case LCP_CI_AP:
if (req_neg.NEG_AP || sizeleft < *inp || *inp < 4) goto badnak;
sizeleft -= *inp;
/*
** If AP is nak'd, we don't care what they want --
** we still don't negotiate
*/
inp += *inp - 1;
break;
case LCP_CI_PFC:
LCP_RNAK_ADD(PFC,2);
break;
case LCP_CI_ACFC:
LCP_RNAK_ADD(ACFC,2);
break;
default:
if (sizeleft < *inp || *inp < 2) goto badnak;
sizeleft -= *inp;
inp += *inp - 1;
} /* Endswtich */
code = *inp++;
} /* Endwhile */
if (fsm->STATE < PPP_STATE_OPENED) {
lcp_ptr->RECV_NEG = req_neg;
} /* Endif */
return TRUE;
badnak:
return FALSE;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_recvconfrej
* Returned Value : TRUE or FALSE
* Comments :
* Called by PPPFSM_recvconfnak. Parses a ConfRej packet.
* This function should not modify any state if the rej is bad.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean LCP_recvconfrej
(
PPPFSM_CFG_PTR fsm
/* [IN] - State Machine */
)
{ /* Body */
LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
uchar_ptr inp = fsm->DATA;
uint_32 sizeleft = fsm->LENGTH;
uint_32 aplen;
PPP_OPT req_opt = lcp_ptr->RECV_OPT;
LCP_NEG req_neg = lcp_ptr->RECV_NEG;
uchar code;
#define LCP_RREJ(ci,len) \
if (sizeleft < len) goto badrej; \
if (*inp++ != len) goto badrej; \
sizeleft -= len; \
req_neg.NEG_ ## ci = 0; \
req_opt.ci = PPP_DEFAULT_OPTIONS.ci
/*
** Rej'd codes must be in the same order as they were in the ConfReq
*/
code = *inp++;
if (sizeleft && req_neg.NEG_MRU && (code == LCP_CI_MRU)) {
LCP_RREJ(MRU,4);
if (req_neg.MRU != ntohs(inp)) goto badrej; inp += 2;
code = *inp++;
} /* Endif */
if (sizeleft && req_neg.NEG_ACCM && (code == LCP_CI_ACCM)) {
LCP_RREJ(ACCM,6);
if (req_neg.ACCM != ntohl(inp)) goto badrej; inp += 4;
code = *inp++;
} /* Endif */
if (sizeleft && req_neg.NEG_AP && (code == LCP_CI_AP)) {
switch (req_neg.AP) {
case PPP_PROT_CHAP: aplen = 5; break;
default: aplen = 4; break;
} /* Endswitch */
LCP_RREJ(AP,aplen);
if (req_neg.AP != ntohs(inp)) goto badrej; inp += 2;
switch (req_neg.AP) {
case PPP_PROT_CHAP:
if (5 != ntohc(inp)) goto badrej; /* Only MD5 supported */
inp++;
break;
} /* Endswitch */
req_opt.AP_Start = PPP_DEFAULT_OPTIONS.AP_Start;
code = *inp++;
} /* Endif */
if (sizeleft && req_neg.NEG_PFC && (code == LCP_CI_PFC)) {
LCP_RREJ(PFC,2);
code = *inp++;
} /* Endif */
if (sizeleft && req_neg.NEG_ACFC && (code == LCP_CI_ACFC)) {
LCP_RREJ(ACFC,2);
code = *inp++;
} /* Endif */
if (sizeleft) goto badrej;
if (fsm->STATE < PPP_STATE_OPENED) {
lcp_ptr->RECV_OPT = req_opt;
lcp_ptr->RECV_NEG = req_neg;
} /* Endif */
return TRUE;
badrej:
return FALSE;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_recvconfreq
* Returned Value : number of bytes written
* Comments :
* Called by PPPFSM_recvconfreq. Parses a ConfReq packet.
* Builds a ConfAck/ConfNak/ConfRej packet out of fsm->PACKET,
* and sets fsm->CODE appropriately.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static uint_32 LCP_recvconfreq
(
PPPFSM_CFG_PTR fsm,
/* [IN] - State Machine */
boolean reject
/* [IN] - whether to ConfRej if we disagree */
)
{ /* Body */
LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
uchar_ptr inp = fsm->DATA;
uchar_ptr nakp, rejp;
uint_32 sizeleft = fsm->LENGTH;
uint_32 naklen, rejlen;
boolean apneg = FALSE;
PPP_OPT req_opt = lcp_ptr->SEND_OPT;
uchar code;
uchar cicode, cilen;
/* Start CR 2207 */
#if PPP_SECRETS_NOT_SHARED
PPP_CFG_PTR ppp_ptr = lcp_ptr->HANDLE;
#endif
/* End CR 2207 */
#define CI_REJECT(n) \
inp -= n; \
code = CP_CODE_CONF_REJ; \
rejlen += cilen; \
while (cilen--) *rejp++ = *inp++
#define CI_NAK \
if (code != CP_CODE_CONF_REJ) { \
code = CP_CODE_CONF_NAK; \
if (reject) { \
inp -= cilen; \
naklen += cilen; \
while (cilen--) *nakp++ = *inp++; \
} else { \
apneg = FALSE;
#define CI_ENDNAK \
} /* Endif */ \
} /* Endif */
#define CI_NAKAP(n) \
if (code != CP_CODE_CONF_REJ) { \
code = CP_CODE_CONF_NAK; \
if (reject) { \
inp -= n; \
naklen += cilen; \
while (cilen--) *nakp++ = *inp++; \
} else { \
apneg = TRUE; \
inp += cilen - n; \
} /* Endif */ \
} else { \
inp += cilen - n; \
} /* Endif */
/*
** Process all requested codes
*/
rejp = nakp = inp;
rejlen = naklen = 0;
code = CP_CODE_CONF_ACK;
while (sizeleft) {
/* check remaining length */
if (sizeleft < inp[1] || inp[1] < 2) {
code = CP_CODE_CONF_REJ;
rejlen += sizeleft;
while (sizeleft--) *rejp++ = *inp++;
break;
} /* Endif */
cicode = *inp++;
sizeleft -= cilen = *inp++;
switch (cicode) {
case LCP_CI_MRU:
if (cilen != 4) {
CI_REJECT(2);
break;
} /* Endif */
/* Accept any MRU no smaller than 68 bytes */
req_opt.MRU = ntohs(inp); inp += 2;
if (req_opt.MRU > DEFAULT_MRU) {
req_opt.MRU = DEFAULT_MRU;
} else if (req_opt.MRU < MINIMUM_MRU) {
CI_NAK {
*nakp++ = LCP_CI_MRU;
naklen += *nakp++ = 4;
req_opt.MRU = MINIMUM_MRU;
htons(nakp, req_opt.MRU); nakp += 2;
} CI_ENDNAK;
} /* Endif */
break;
case LCP_CI_ACCM:
if (cilen != 6) {
CI_REJECT(2);
break;
} /* Endif */
/* If we want any characters not in their ACCM, nak it */
req_opt.ACCM = ntohl(inp); inp += 4;
if ((req_opt.ACCM & _PPP_ACCM) != _PPP_ACCM) {
CI_NAK {
*nakp++ = LCP_CI_ACCM;
naklen += *nakp++ = 6;
req_opt.ACCM |= _PPP_ACCM;
htonl(nakp, req_opt.ACCM); nakp += 4;
} CI_ENDNAK;
} /* Endif */
break;
/*
** AP is unusual in that it is a variable length
** option. Thus it is possible that we may want
** to nak AP and make a suggestion longer than
** the peer's request.
**
** This is bad.
**
** It's bad because this function wants to reuse
** the incoming ConfReq to build the reply, and
** in this case, it is possible for nakp to
** overtake inp, thus overwriting an option not
** yet parsed.
**
** So we do the following: If we decide to nak
** the requested AP, we just set apneg=TRUE and
** append the nak'd AP at the end of our ConfNak
** after we've completed parsing the ConfReq.
**
** Note that we won't nak AP if we generate
** nak's for other options afterward, because
** the RFC states that nak'd options MUST be in
** the same order that they were in the ConfReq.
*/
case LCP_CI_AP:
if (cilen < 4) {
CI_REJECT(2);
break;
} /* Endif */
/* If we don't have any secrets, reject AP */
/* Start CR 2207 */
if (!(PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET) || PPP_SECRET(ppp_ptr,_PPP_CHAP_LSECRETS))) {
/* End CR 2207 */
CI_REJECT(2);
break;
} /* Endif */
/* Check the desired authentication protocol */
req_opt.AP = ntohs(inp); inp += 2;
switch (req_opt.AP) {
/* Accept PAP only if we have a secret */
case PPP_PROT_PAP:
if (cilen != 4) {
CI_REJECT(4);
break;
/* Start CR 2207 */
} else if (PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET) == NULL) {
/* End CR 2207 */
CI_NAKAP(4);
break;
} /* Endif */
req_opt.AP_Start = PAP_send;
break;
/* Accept CHAP only if we have a secrets table */
case PPP_PROT_CHAP:
if (cilen != 5) {
CI_REJECT(4);
break;
/* Start CR 2207 */
} else if (PPP_SECRET(ppp_ptr,_PPP_CHAP_LSECRETS) == NULL) {
/* End CR 2207 */
CI_NAKAP(4);
break;
} else if (*inp++ != 5) { /* Only MD5 supported */
CI_NAKAP(5);
break;
} /* Endif */
req_opt.AP_Start = CHAP_open;
break;
default:
CI_NAKAP(4);
break;
} /* Endswitch */
break;
case LCP_CI_MAGIC:
if (cilen != 6) {
CI_REJECT(2);
break;
} /* Endif */
inp += 4;
break;
case LCP_CI_PFC:
if (cilen != 2) {
CI_REJECT(2);
break;
} /* Endif */
req_opt.PFC = TRUE;
break;
case LCP_CI_ACFC:
if (cilen != 2) {
CI_REJECT(2);
break;
} /* Endif */
req_opt.ACFC = TRUE;
break;
default:
CI_REJECT(2);
break;
} /* Endswitch */
} /* Endwhile */
/*
** If we wanted to send additional naks for unsent codes, they
** would go here, at *nakp.
*/
if (code == CP_CODE_CONF_ACK) {
lcp_ptr->SEND_OPT = req_opt;
sizeleft = fsm->LENGTH;
} else if (code == CP_CODE_CONF_REJ) {
sizeleft = rejlen;
} else if (reject) {
code = CP_CODE_CONF_REJ;
sizeleft = naklen;
} else { /* if code == NAK */
/* We want to nak AP, and we didn't nak anything else after it */
if (apneg) {
/* Start CR 2207 */
if (PPP_SECRET(ppp_ptr,_PPP_CHAP_LSECRETS)) {
/* End CR 2207 */
*nakp++ = LCP_CI_AP;
naklen += *nakp++ = 5;
htons(nakp, PPP_PROT_CHAP); nakp += 2;
*nakp++ = 5; /* Only MD5 supported */
/* Start CR 2207 */
} else if (PPP_SECRET(ppp_ptr,_PPP_PAP_LSECRET)) {
/* End CR 2207 */
*nakp++ = LCP_CI_AP;
naklen += *nakp++ = 4;
htons(nakp, PPP_PROT_PAP); nakp += 2;
} /* Endif */
} /* Endif */
sizeleft = naklen;
} /* Endif */
fsm->CODE = code;
return sizeleft;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_recvcoderej
* Returned Value : TRUE or FALSE
* Comments :
* Called by PPPFSM_Recvcoderej. Returns TRUE if the rejected
* code is catastrophic.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean LCP_recvcoderej
(
PPPFSM_CFG_PTR fsm
/* [IN] - State Machine */
)
{ /* Body */
uchar code = *fsm->DATA;
return (code >= 1 && code <= 7);
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_up
* Returned Value : TRUE or FALSE
* Comments :
* Called by the FSM when entering the OPENED state. Returns
* TRUE if the link can be allowed to remain up.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static boolean LCP_up
(
PPPFSM_CFG_PTR fsm
/* [IN] - State Machine */
)
{ /* Body */
PPP_CFG_PTR ppp_ptr = fsm->HANDLE;
LCP_CFG_PTR lcp_ptr = fsm->PRIVATE;
PPP_CALL_INTERNAL_PTR callauth_ptr = &ppp_ptr->LCP_CALL[PPP_CALL_AUTH_FAIL];
/* Start CR 2207 */
if ((PPP_SECRET(ppp_ptr,_PPP_PAP_RSECRETS) || PPP_SECRET(ppp_ptr,_PPP_CHAP_RSECRETS))
/* End CR 2207 */
&& !lcp_ptr->RECV_OPT.AP) {
if (callauth_ptr->CALLBACK) {
(*callauth_ptr->CALLBACK)(callauth_ptr->PARAM);
} /* Endif */
return FALSE;
} /* Endif */
/* Initialize the authentication protocols */
PAP_init(fsm->HANDLE);
CHAP_init(fsm->HANDLE);
PPP_mutex_lock(&ppp_ptr->MUTEX);
ppp_ptr->LINK_STATE = TRUE;
ppp_ptr->LINK_AUTH = (lcp_ptr->RECV_OPT.AP == 0);
ppp_ptr->RECV_OPTIONS = &lcp_ptr->RECV_OPT;
ppp_ptr->SEND_OPTIONS = &lcp_ptr->SEND_OPT;
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_S_ACCM, &lcp_ptr->SEND_OPT.ACCM);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_R_ACCM, &lcp_ptr->RECV_OPT.ACCM);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_S_PFC, &lcp_ptr->SEND_OPT.PFC);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_R_PFC, &lcp_ptr->RECV_OPT.PFC);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_S_ACFC, &lcp_ptr->SEND_OPT.ACFC);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_R_ACFC, &lcp_ptr->RECV_OPT.ACFC);
PPP_mutex_unlock(&ppp_ptr->MUTEX);
/* Start CR 2158 */
if ((lcp_ptr->SEND_OPT.AP != 0) || (lcp_ptr->RECV_OPT.AP != 0)) {
/* The link requires authentication */
/* If the peer requested authentication, send it */
if (lcp_ptr->SEND_OPT.AP != 0) {
(*lcp_ptr->SEND_OPT.AP_Start)(fsm->HANDLE);
} /* Endif */
/*
** Note: we really should call RECV_OPT.AP_Start() before
** setting LINK_STATE (but still call PPP_LINK_UP() after),
** but, LCP_up() is always called from the context of the
** PPP rx task, so there isn't a problem.
**
** (There would be a problem if an AP packet could be processed
** after setting LINK_STATE=TRUE, LINK_AUTH=FALSE and before
** AP_Start() could initialize the AP's state. But there isn't
** a problem because we're always in the context of the only task
** that does this processing.)
*/
/* If we requested authentication, wait for it */
if (lcp_ptr->RECV_OPT.AP != 0) {
(*lcp_ptr->RECV_OPT.AP_Start)(fsm->HANDLE);
}
} else {
/* Otherwise, call the application's PPP_LINK_UP callback */
PPP_up(ppp_ptr);
/* End CR 2158 */
} /* Endif */
return TRUE;
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : LCP_down
* Returned Value : void
* Comments :
* Called by the FSM when leaving the OPENED state.
*
*END*-----------------------------------------------------------------*/
#if RTCSCFG_ENABLE_IP4
static void LCP_down
(
PPPFSM_CFG_PTR fsm
/* [IN] - State Machine */
)
{ /* Body */
PPP_CFG_PTR ppp_ptr = fsm->HANDLE;
PPP_CALL_INTERNAL_PTR calldown_ptr = &ppp_ptr->LCP_CALL[PPP_CALL_LINK_DOWN];
boolean linkauth;
/* Stop compression */
CCP_lowerdown(fsm->HANDLE);
PPP_mutex_lock(&ppp_ptr->MUTEX);
ppp_ptr->LINK_STATE = FALSE;
linkauth = ppp_ptr->LINK_AUTH;
ppp_ptr->RECV_OPTIONS = &PPP_DEFAULT_OPTIONS;
ppp_ptr->SEND_OPTIONS = &PPP_DEFAULT_OPTIONS;
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_S_ACCM, &PPP_DEFAULT_OPTIONS.ACCM);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_R_ACCM, &PPP_DEFAULT_OPTIONS.ACCM);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_S_PFC, &PPP_DEFAULT_OPTIONS.PFC);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_R_PFC, &PPP_DEFAULT_OPTIONS.PFC);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_S_ACFC, &PPP_DEFAULT_OPTIONS.ACFC);
_iopcb_ioctl(ppp_ptr->DEVICE, IOPCB_IOCTL_R_ACFC, &PPP_DEFAULT_OPTIONS.ACFC);
PPP_mutex_unlock(&ppp_ptr->MUTEX);
/* Call the application's PPP_LINK_DOWN callback */
if (calldown_ptr->CALLBACK && linkauth) {
(*calldown_ptr->CALLBACK)(calldown_ptr->PARAM);
} /* Endif */
} /* Endbody */
#endif /* RTCSCFG_ENABLE_IP4 */
/*FUNCTION*-------------------------------------------------------------
*
* Function Name : PPP_up
* Returned Value : void
* Comments :
* Called when the PPP link goes up. Called either by LCP
* when entering the OPENED state, or by an authentication
* protocol once the peer has authenticated itself.
*
*END*-----------------------------------------------------------------*/
void PPP_up
(
_ppp_handle handle
/* [IN] - the PPP state structure */
)
{ /* Body */
#if RTCSCFG_ENABLE_IP4
PPP_CFG_PTR ppp_ptr = handle;
PPP_CALL_INTERNAL_PTR callup_ptr = &ppp_ptr->LCP_CALL[PPP_CALL_LINK_UP];
if (callup_ptr->CALLBACK) {
(*callup_ptr->CALLBACK)(callup_ptr->PARAM);
} /* Endif */
/* Try to negotiate compression */
CCP_lowerup(handle);
#endif /* RTCSCFG_ENABLE_IP4 */
} /* Endbody */
/* EOF */