621 lines
15 KiB
C++
621 lines
15 KiB
C++
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
receive.cpp
|
|
|
|
Abstract:
|
|
|
|
Handle received packets.
|
|
|
|
Revision History:
|
|
|
|
07-18-00 vadimg created
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
VOID (*gReceive[])(DWORD CpIndex, PPP_CONFIG *pRecvConfig) = {
|
|
NULL,
|
|
ReceiveConfigReq,
|
|
ReceiveConfigAck,
|
|
ReceiveConfigNakRej,
|
|
ReceiveConfigNakRej,
|
|
ReceiveTermReq,
|
|
ReceiveTermAck,
|
|
ReceiveCodeRej,
|
|
NULL,
|
|
ReceiveEchoReq,
|
|
ReceiveEchoReply,
|
|
ReceiveDiscardReq
|
|
};
|
|
|
|
/***************************************************************************\
|
|
* ReceiveConfigReq
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveConfigReq(DWORD CpIndex, PPP_CONFIG *pRecvConfig)
|
|
{
|
|
PPP_PACKET *pSendPacket = GetSendPacket();
|
|
PPP_CONFIG *pSendConfig = (PPP_CONFIG*)pSendPacket->Data;
|
|
BOOL fAcked;
|
|
|
|
switch (gInfo.State) {
|
|
case FSM_OPENED:
|
|
if (!FsmThisLayerDown(CpIndex)) {
|
|
return;
|
|
}
|
|
if (!FsmSendConfigReq(CpIndex)) {
|
|
return;
|
|
}
|
|
if (!FsmSendConfigResult(CpIndex, pRecvConfig, &fAcked)) {
|
|
return;
|
|
}
|
|
|
|
gInfo.State = fAcked ? FSM_ACK_SENT : FSM_REQ_SENT;
|
|
break;
|
|
|
|
case FSM_STOPPED:
|
|
|
|
InitRestartCounters();
|
|
|
|
if (!FsmSendConfigReq(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
// fall through
|
|
|
|
case FSM_REQ_SENT:
|
|
case FSM_ACK_SENT:
|
|
if (!FsmSendConfigResult(CpIndex, pRecvConfig, &fAcked)) {
|
|
return;
|
|
}
|
|
|
|
gInfo.State = fAcked ? FSM_ACK_SENT : FSM_REQ_SENT;
|
|
break;
|
|
|
|
case FSM_ACK_RCVD:
|
|
if (!FsmSendConfigResult(CpIndex, pRecvConfig, &fAcked)) {
|
|
return;
|
|
}
|
|
|
|
if (fAcked) {
|
|
gInfo.State = FSM_OPENED;
|
|
FsmThisLayerUp(CpIndex);
|
|
}
|
|
break;
|
|
|
|
case FSM_CLOSED:
|
|
FsmSendTermAck(CpIndex, pRecvConfig);
|
|
break;
|
|
|
|
case FSM_CLOSING:
|
|
case FSM_STOPPING:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveConfigAck
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveConfigAck(DWORD CpIndex, PPP_CONFIG *pRecvConfig)
|
|
{
|
|
// The Id of the Ack HAS to match the Id of the last request sent
|
|
// If it is different, then we should silently discard it.
|
|
if (pRecvConfig->Id != gInfo.LastId) {
|
|
return;
|
|
}
|
|
|
|
ClearTimeout();
|
|
|
|
switch (gInfo.State) {
|
|
case FSM_REQ_SENT:
|
|
if (!FsmConfigResultReceived(CpIndex, pRecvConfig)) {
|
|
return;
|
|
}
|
|
|
|
InitRestartCounters();
|
|
gInfo.State = FSM_ACK_RCVD;
|
|
break;
|
|
|
|
case FSM_ACK_SENT:
|
|
if (!FsmConfigResultReceived(CpIndex, pRecvConfig)) {
|
|
return;
|
|
}
|
|
|
|
InitRestartCounters();
|
|
gInfo.State = FSM_OPENED;
|
|
FsmThisLayerUp(CpIndex);
|
|
break;
|
|
|
|
case FSM_OPENED:
|
|
if (!FsmThisLayerDown(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
// fall through
|
|
|
|
case FSM_ACK_RCVD:
|
|
if (!FsmSendConfigReq(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
gInfo.State = FSM_REQ_SENT;
|
|
break;
|
|
|
|
case FSM_CLOSED:
|
|
case FSM_STOPPED:
|
|
// Out of Sync; kill the remote
|
|
FsmSendTermAck(CpIndex, pRecvConfig);
|
|
break;
|
|
|
|
case FSM_CLOSING:
|
|
case FSM_STOPPING:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveConfigNakRej
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveConfigNakRej(DWORD CpIndex, PPP_CONFIG *pRecvConfig)
|
|
{
|
|
// The Id of the Nak/Rej HAS to match the Id of the last request sent
|
|
// If it is different, then we should silently discard it.
|
|
if (pRecvConfig->Id != gInfo.LastId) {
|
|
return;
|
|
}
|
|
|
|
ClearTimeout();
|
|
|
|
switch (gInfo.State) {
|
|
case FSM_REQ_SENT:
|
|
case FSM_ACK_SENT:
|
|
if (!FsmConfigResultReceived(CpIndex, pRecvConfig)) {
|
|
return;
|
|
}
|
|
|
|
InitRestartCounters();
|
|
|
|
if (!FsmSendConfigReq(CpIndex)) {
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case FSM_OPENED:
|
|
if (!FsmThisLayerDown(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
// fall through
|
|
|
|
case FSM_ACK_RCVD:
|
|
if (!FsmSendConfigReq(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
gInfo.State = FSM_REQ_SENT;
|
|
break;
|
|
|
|
case FSM_CLOSED:
|
|
case FSM_STOPPED:
|
|
// Out of Sync; kill the remote
|
|
FsmSendTermAck(CpIndex, pRecvConfig);
|
|
break;
|
|
|
|
case FSM_CLOSING:
|
|
case FSM_STOPPING:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveTermReq
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveTermReq(DWORD CpIndex, PPP_CONFIG *pConfig)
|
|
{
|
|
switch (gInfo.State) {
|
|
case FSM_OPENED:
|
|
if (!FsmThisLayerDown(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
FsmSendTermAck(CpIndex, pConfig);
|
|
gInfo.State = FSM_STOPPING;
|
|
break;
|
|
|
|
case FSM_ACK_RCVD:
|
|
case FSM_ACK_SENT:
|
|
case FSM_REQ_SENT:
|
|
FsmSendTermAck(CpIndex, pConfig);
|
|
gInfo.State = FSM_REQ_SENT;
|
|
break;
|
|
|
|
case FSM_CLOSED:
|
|
case FSM_CLOSING:
|
|
case FSM_STOPPED:
|
|
case FSM_STOPPING:
|
|
FsmSendTermAck(CpIndex, pConfig);
|
|
break;
|
|
}
|
|
|
|
FsmThisLayerFinished(CpIndex);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveTermAck
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveTermAck(DWORD CpIndex, PPP_CONFIG *pRecvConfig)
|
|
{
|
|
// The Id of the Term Ack HAS to match the Id of the last request sent
|
|
// If it is different, then we should silently discard it.
|
|
if (pRecvConfig->Id != gInfo.LastId) {
|
|
return;
|
|
}
|
|
|
|
switch (gInfo.State) {
|
|
case FSM_OPENED:
|
|
if (!FsmThisLayerDown(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
if (!FsmSendConfigReq(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
gInfo.State = FSM_REQ_SENT;
|
|
break;
|
|
|
|
case FSM_ACK_RCVD:
|
|
gInfo.State = FSM_REQ_SENT;
|
|
break;
|
|
|
|
case FSM_CLOSING:
|
|
case FSM_STOPPING:
|
|
if (!FsmThisLayerFinished(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
gInfo.State = (gInfo.State == FSM_CLOSING) ? FSM_CLOSED : FSM_STOPPED;
|
|
break;
|
|
|
|
case FSM_REQ_SENT:
|
|
case FSM_ACK_SENT:
|
|
case FSM_CLOSED:
|
|
case FSM_STOPPED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveUnknownCode
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveUnknownCode(DWORD CpIndex, PPP_CONFIG *pConfig)
|
|
{
|
|
switch (gInfo.State) {
|
|
case FSM_STOPPED:
|
|
case FSM_STOPPING:
|
|
case FSM_OPENED:
|
|
case FSM_ACK_SENT:
|
|
case FSM_ACK_RCVD:
|
|
case FSM_REQ_SENT:
|
|
case FSM_CLOSING:
|
|
case FSM_CLOSED:
|
|
FsmSendCodeReject(CpIndex, pConfig);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveDiscardReq
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveDiscardReq(DWORD CpIndex, PPP_CONFIG *pConfig)
|
|
{
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveEchoReq
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveEchoReq(DWORD CpIndex, PPP_CONFIG *pConfig)
|
|
{
|
|
// Silently discard this packet if LCP is not in an opened state
|
|
if (!IsLcpOpened()) {
|
|
return;
|
|
}
|
|
|
|
switch (gInfo.State) {
|
|
case FSM_STOPPED:
|
|
case FSM_STOPPING:
|
|
case FSM_ACK_SENT:
|
|
case FSM_ACK_RCVD:
|
|
case FSM_REQ_SENT:
|
|
case FSM_CLOSING:
|
|
case FSM_CLOSED:
|
|
case FSM_STARTING:
|
|
case FSM_INITIAL:
|
|
break;
|
|
|
|
case FSM_OPENED:
|
|
FsmSendEchoReply(CpIndex, pConfig);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveEchoReply
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveEchoReply(DWORD CpIndex, PPP_CONFIG *pConfig)
|
|
{
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveCodeRej
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveCodeRej(DWORD CpIndex, PPP_CONFIG *pConfig)
|
|
{
|
|
pConfig = (PPP_CONFIG*)pConfig->Data;
|
|
|
|
// First check to see if these codes may be rejected without
|
|
// affecting implementation. Permitted code rejects
|
|
if (CpIndex == CP_LCP) {
|
|
switch (pConfig->Code) {
|
|
case CONFIG_REQ:
|
|
case CONFIG_ACK:
|
|
case CONFIG_NAK:
|
|
case CONFIG_REJ:
|
|
case TERM_REQ:
|
|
case TERM_ACK:
|
|
case CODE_REJ:
|
|
case PROT_REJ:
|
|
case ECHO_REQ:
|
|
case ECHO_REPLY:
|
|
case DISCARD_REQ:
|
|
// Unpermitted code rejects.
|
|
break;
|
|
|
|
default:
|
|
// Permitted code rejects, we can still work.
|
|
switch (gInfo.State) {
|
|
case FSM_ACK_RCVD:
|
|
gInfo.State = FSM_REQ_SENT;
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
// Actually the remote side did not reject the protocol, it rejected
|
|
// the code. But for all practical purposes we cannot talk with
|
|
// the corresponding CP on the remote side. This is actually an
|
|
// implementation error in the remote side.
|
|
gInfo.dwError = ERROR_PPP_NOT_CONVERGING;
|
|
|
|
switch (gInfo.State) {
|
|
case FSM_CLOSING:
|
|
if (!FsmThisLayerFinished(CpIndex)) {
|
|
return;
|
|
}
|
|
gInfo.State = FSM_CLOSED;
|
|
break;
|
|
|
|
case FSM_REQ_SENT:
|
|
case FSM_ACK_RCVD:
|
|
case FSM_ACK_SENT:
|
|
case FSM_STOPPING:
|
|
if (!FsmThisLayerFinished(CpIndex)) {
|
|
return;
|
|
}
|
|
gInfo.State = FSM_STOPPED;
|
|
break;
|
|
|
|
case FSM_OPENED:
|
|
if (!FsmThisLayerDown(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
InitRestartCounters();
|
|
FsmSendTermReq(CpIndex);
|
|
gInfo.State = FSM_STOPPING;
|
|
break;
|
|
|
|
case FSM_CLOSED:
|
|
case FSM_STOPPED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* ReceiveProtocolRej
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID ReceiveProtocolRej(PPP_PACKET *pPacket)
|
|
{
|
|
PPP_CONFIG *pRecvConfig = (PPP_CONFIG*)pPacket->Data;
|
|
DWORD dwProtocol = WireToHostFormat16(pRecvConfig->Data);
|
|
DWORD CpIndex;
|
|
|
|
CpIndex = GetCpIndexFromProtocol(dwProtocol);
|
|
|
|
if (CpIndex == (DWORD)-1) {
|
|
return;
|
|
}
|
|
|
|
if (CpIndex == CP_LCP) {
|
|
gInfo.dwError = ERROR_PPP_NOT_CONVERGING;
|
|
return;
|
|
}
|
|
|
|
// If LCP is not in the opened state we silently discard this packet
|
|
if (!IsLcpOpened()) {
|
|
return;
|
|
}
|
|
|
|
gInfo.dwError = ERROR_PPP_CP_REJECTED;
|
|
|
|
switch (gInfo.State) {
|
|
case FSM_CLOSING:
|
|
if (!FsmThisLayerFinished(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
gInfo.State = FSM_CLOSED;
|
|
break;
|
|
|
|
case FSM_REQ_SENT:
|
|
case FSM_ACK_RCVD:
|
|
case FSM_ACK_SENT:
|
|
case FSM_STOPPING:
|
|
if (!FsmThisLayerFinished(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
gInfo.State = FSM_STOPPED;
|
|
break;
|
|
|
|
case FSM_OPENED:
|
|
if (!FsmThisLayerDown(CpIndex)) {
|
|
return;
|
|
}
|
|
|
|
InitRestartCounters();
|
|
FsmSendTermReq(CpIndex);
|
|
gInfo.State = FSM_STOPPING;
|
|
break;
|
|
|
|
case FSM_CLOSED:
|
|
case FSM_STOPPED:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* FsmConfigResultReceived
|
|
*
|
|
\***************************************************************************/
|
|
|
|
BOOL FsmConfigResultReceived(DWORD CpIndex, PPP_CONFIG *pRecvConfig)
|
|
{
|
|
DWORD dwRetCode;
|
|
|
|
switch (pRecvConfig->Code) {
|
|
case CONFIG_NAK:
|
|
dwRetCode = gCpTable[CpIndex].CP_ConfigNakReceived(pRecvConfig);
|
|
break;
|
|
|
|
case CONFIG_ACK:
|
|
dwRetCode = gCpTable[CpIndex].CP_ConfigAckReceived(pRecvConfig);
|
|
break;
|
|
|
|
case CONFIG_REJ:
|
|
dwRetCode = gCpTable[CpIndex].CP_ConfigRejReceived(pRecvConfig);
|
|
break;
|
|
|
|
default:
|
|
return FALSE;
|
|
}
|
|
|
|
if (dwRetCode != NO_ERROR) {
|
|
if (dwRetCode == ERROR_PPP_INVALID_PACKET) {
|
|
return TRUE;
|
|
} else {
|
|
FsmClose(CpIndex);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* FsmReceive
|
|
*
|
|
\***************************************************************************/
|
|
|
|
VOID FsmReceive(PPP_PACKET *pPacket, DWORD dwPacketLength)
|
|
{
|
|
DWORD dwProtocol;
|
|
DWORD CpIndex;
|
|
PPP_CONFIG *pRecvConfig;
|
|
DWORD dwLength;
|
|
BOOL fAuth = FALSE;
|
|
|
|
// Validate length of packet
|
|
if (dwPacketLength < (PPP_PACKET_HDR_LEN + PPP_CONFIG_HDR_LEN)) {
|
|
return;
|
|
}
|
|
|
|
dwProtocol = WireToHostFormat16(pPacket->Protocol);
|
|
CpIndex = GetCpIndexFromProtocol(dwProtocol);
|
|
if (CpIndex == (DWORD)-1) {
|
|
DbgPrint("Unknown protocol in PPP packet\n");
|
|
return;
|
|
}
|
|
|
|
switch (gInfo.Phase) {
|
|
case PPP_AP:
|
|
if (CpIndex == GetCpIndexFromProtocol(gLcp.Remote.Work.AP)) {
|
|
fAuth = TRUE;
|
|
break;
|
|
}
|
|
|
|
// fall through
|
|
|
|
case PPP_LCP:
|
|
if (CpIndex == CP_LCP) {
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
pRecvConfig = (PPP_CONFIG*)pPacket->Data;
|
|
|
|
dwLength = WireToHostFormat16(pRecvConfig->Length);
|
|
|
|
if (dwLength > (dwPacketLength - PPP_PACKET_HDR_LEN) ||
|
|
(dwLength < PPP_CONFIG_HDR_LEN)) {
|
|
return;
|
|
}
|
|
|
|
// Not in ProcessPacket table since parameters to this are different.
|
|
if (CpIndex == CP_LCP && pRecvConfig->Code == PROT_REJ) {
|
|
ReceiveProtocolRej(pPacket);
|
|
return;
|
|
}
|
|
|
|
// Make sure that the protocol can handle the config code sent.
|
|
if (pRecvConfig->Code == 0 ||
|
|
pRecvConfig->Code > gCpTable[CpIndex].Recognize) {
|
|
ReceiveUnknownCode(CpIndex, pRecvConfig);
|
|
return;
|
|
}
|
|
|
|
if (fAuth) {
|
|
ApWork(CpIndex, pRecvConfig);
|
|
} else {
|
|
gReceive[pRecvConfig->Code](CpIndex, pRecvConfig);
|
|
}
|
|
}
|
|
|