PPP packet analysis and code encapsulation sharing

1. Introduction:

PPP (Point-to-Point Protocol) belongs to the data link layer protocol. This link provides full-duplex operation and transmits data packets in order.

The PPP protocol is a protocol set including: LCP (Link Control Protocol) link control protocol, and NCP (Network Control Protocol) network control protocol.

The PPP protocol goes through five phases: initialization phase, LCP negotiation phase (including authentication), NCP (IPCP) negotiation phase, PPP session phase, and network termination phase.

insert image description here
The most important thing to establish a PPP connection is to go through three stages:
The first stage: LCP connection negotiation
In this stage, the basic communication method will be selected. The devices at both ends of the link send LCP datagram configuration requests (Configure-Request) to each other through LCP, and the other party agrees to receive and send LCP datagram configuration responses (Configure-Ack) to each other. Once a Configure-Ack packet is sent and received, the exchange is complete and the LCP is enabled.

The second stage: CHAP password authentication
In this stage, the client will send its identity to the remote access server. The server sends a PPP CHAP security authentication challenge to the user, and then the user sends a PPP CHAP security authentication response to the server, and the server sends a PPP CHAP security authentication success to the user.
This stage uses a security verification method to prevent third parties from stealing data or pretending to be a remote client to take over the connection with the client. Proceeding from the authentication phase to the network layer protocol phase is prohibited until authentication is complete. If authentication fails, the authenticator should transition to the link termination phase.

The third stage: NCP network layer protocol configuration
After the authentication stage is completed, various network control protocols (NCP) selected in the link creation stage (stage 1) will be invoked. The selected NCP solves the high-level protocol issues on the link, for example, IP Control Protocol (IPCP) can assign dynamic IP addresses to dial-in users at this stage. At this stage, the user first sends a PPP NCP network control packet to the server (network protocol configuration, requiring the server to provide IP address and DNS information), and then the server sends a configuration request PPP NCP network control packet to the user (assigning an IP address to the user ), the user sends a configuration response PPP NCP network control packet to the server (accepting the assigned IP address), and finally the server sends a configuration response PPP NCP network control packet to the user (agreeing to the user's IP address and DNS address).

In this way, after three stages, a complete link is established, and the user can send IP data packets to the server.

What is the PDP context:
The 4G module first requests the gateway to assign an IP address (called a PDP address, which can be regarded as a private address inside the mobile gateway), and then communicates with the external data network through the gateway. The process of requesting the gateway to assign an address is called In order to activate PDP, the PDP address is like the phone number on the work order when you open a wired phone, and the PDP context is the work order for this phone, which not only has the phone number assigned to you, but also other corresponding to this phone. properties, information about other functions. The PDP context is a structure, and the PDP address is just a member of the structure. In addition, it also includes QoS, APN, etc. These are the contents of the PDP context. In the PDP context, there is an important parameter
APN, APN is The 4G module is used to inform the gateway which external data network to access (external packet data network, including enterprise intranet, Internet, WAP website, industry intranet, etc.); Incoming and outgoing phone calls within the province", "Only support domestic phone inbound and outbound calls", and "Global inbound and outbound calls" are equivalent to telephones.

2. PPP frame:

insert image description here
Protocol (2 bytes):
0xC021 LCP protocol
0xC023 PAP protocol
0x8021 IPCP protocol
0x0021 IP protocol

Coding (1 byte):
0x01 Configuration request (Req)
0x02 Accept configuration request (Ack)
0x03 Configuration request accepted, others rejected (Nak)
0x04 Configuration request does not recognize or is not accepted (Rej)
0x05 Terminate link
0x06 Terminate confirmation
Others
insert image description here

2.1 PPP escape characters:

Each frame of PPP data frame starts and ends with the identification character 0x7E;
since the value of the identification character is 0x7E, when this character appears in the information field, PPP needs to escape it;
when PPP uses asynchronous transmission, it Define the escape character as: 0x7D, and use the byte filling RFC-1662 standard; the
byte filling RFC-1662 standard stipulates as follows:
convert each 0x7E character that appears in the information field into a byte sequence (0x7D, 0x5E);
If a 0x7D byte appears in the information field (that is, the same bit combination as the escape character appears), then escape 0x7D into a two-byte sequence (0x7D, 0x5D); if the ASCII code control appears in the information
field character (that is, a character whose value is less than 0x20), add a 0x7D byte in front of the character, and change the encoding of the character at the same time.

2.2 LCP frame analysis

LCP can refer to RFC1661, RFC1661 Chinese version:
http://www.doczj.com/doc/9f1242566-25.html

insert image description here
LCP negotiation process:
insert image description here
(The escape character needs to be used in the LCP message, but the subsequent PAP, CHAP authentication message and NCP message do not need to add the escape character)

LCP negotiation items:
insert image description here

Check code calculation: http://www.ip33.com/crc.html
insert image description here

2.3 PPP certification

2.3.1 PAP

insert image description here

insert image description here
PAP message process:
insert image description here

2.3.2 CHAP

insert image description here
insert image description here
Message interaction process:
insert image description here

2.4 NCP frame analysis:

There are many kinds of NCP, such as IPCP, BCP, and IPv6CP, and the most commonly used one is IPCP (Internet Protocol Control Protocol). The main function of NCP is to negotiate network layer parameters of PPP packets, such as IP address, DNS Server IP address, WINS Server IP address, etc. PPPoE users mainly use IPCP to obtain IP addresses or IP address segments for accessing the network. Currently, the server only supports the IPCP protocol in NCP by default.

IPCP protocol:
The IPCP control protocol is mainly responsible for completing the option negotiation of configuration parameters required for IP network layer protocol communication, and responsible for establishing, enabling and suspending the IP module. During the operation of IPCP, it mainly completes the dynamic negotiation of IP addresses between the two ends of the point-to-point communication device. IPCP packets cannot be exchanged before PPP reaches the network layer protocol stage, and if any IPCP packets arrive before this stage, they will be discarded.

insert image description here
1. The code field is 1 byte long, the identification field is 1 byte long, and the length field is 2 byte long.
2. IPCP negotiates configuration parameter options at the protocol stage of the network layer, and the code field is 0x8021.
3. The code domain field. LCP includes more than a dozen types of messages, while IPCP only includes 7 types of messages, but its message type is only a subset of LCP data messages (only the seven types of messages with LCP code fields from 1 to 7: Config- Request, Config Ack, Config-Nak, Config-Reject, Terminate-Request, Terminate-Ack and Code
Reject), and the link termination message in the actual data message exchange process is generally not used in the network protocol stage.

Message interaction process:
insert image description here
insert image description here

3. PPP message code encapsulation:

PPP_Packet.h

/* ***************************************************************
 * Filename:            Packet.h
 *  @Description:
 *         Packet Creat Check
 *  @Author: ybLin
 * ***************************************************************/
#ifndef __PPP_PACKET_H__
#define __PPP_PACKET_H__
#include <windows.h>
#include "crc.h"
#include <afxext.h> 

#define PPP_FRAME_FLAG		0x7E 	 	//标识字符 
#define PPP_FRAME_ESC		0x7D 	 	//转义字符 
#define PPP_FRAME_ENC		0x20 	 	//编码字符 

#define MAX_RECV_PKT_SIZE	256
#define MIN_RECV_PKT_SIZE 	12

#define PROTOCOL_LCP		0xC021      //LCP协议
#define PROTOCOL_IPCP	    0x8021      //NCP协议:IPCP
#define PROTOCOL_IP		    0x0021      //IP协议
#define PROTOCOL_PAP		0xC023      //PAP认证

extern BYTE g_LcpFirstReq[256];
extern BYTE g_TermReq[256];
extern BYTE g_NcpFirstReq[256];

extern std::string HexToString(const BYTE *pBuffer, size_t iBytes);
extern void DectoHex(int dec, char *hex, int length);
extern unsigned long HextoDec(const unsigned char *hex, int length); 
extern CString Ascii2Hex(CString strASCII);
extern char Char2Hex(char ch);
extern int String2Hex(CString str, char* SendOut);

//执行过程
typedef enum PPP_STATE
{
    PPP_STATE_INIT = 0,
    PPP_STATE_LCP_PERIOD,
    PPP_STATE_LCP_PASS,
    PPP_STATE_NCP_PERIOD,
    PPP_STATE_NCP_NAK,
    PPP_STATE_PPP_PASS,
    PPP_STATE_IP_START,
    PPP_STATE_TERM_LINK
}PPP_STATE_E;

//编码值
typedef enum PPP_CODE
{
    PPP_CODE_REQ = 1,   				//配置请求
    PPP_CODE_ACK,       				//接受配置
    PPP_CODE_NAK,       				//配置请求接受,其他拒绝
    PPP_CODE_REJ,       				//配置请求不认识,或不被接受
    PPP_CODE_TERM_LINK, 				//终止链接
    PPP_CODE_TERM_ACK,  				//终止确认
    PPP_CODE_CODE_REJ,
    PPP_CODE_PROTOCAL_REJ,
    PPP_CODE_ECHO_REQ,
    PPP_CODE_ECHO_REP,
    PPP_CODE_DISCARD_REQ,
    PPP_CODE_IDENTIFICATION,
    PPP_CODE_TIME_REM
}PPP_CODE_E;

//报文解析返回
enum PPP_OPERATE_STATE
{
	PPP_OPERATE_ERROR = -1,
	PPP_OPERATE_NORMAL,
	PPP_OPERATE_NEED_SEND
};

//选项值
typedef struct PPP_OPTION
{
    BYTE bType;
	BYTE bLength;
	BYTE bData[64];
	BOOL bReject;

}PPP_OPTION_T;

//IP头
typedef struct IP_HEADER
{
    BYTE Version;	//4bits
	BYTE IHL;		//4bits
	BYTE Service;
	unsigned short TotalLength;
	unsigned short Identification = 0x0000;
	BYTE FLAG;
	unsigned short FlagFrag;	
	BYTE TTL;
	BYTE protocol;
	BYTE HeaderSum;	
	BYTE SrcIP[4];	
	BYTE DesIP[4];
}IP_HEADER_T;

//ICMP头
typedef struct ICMP_HEADER
{
    BYTE type;
	BYTE code;
	unsigned short sum;
	unsigned short identifier;
	unsigned short sequence = 0x0000;
}ICMP_HEADER_T;

//IP
#define		IP_ICMP			0x01
#define		IP_TCP			0x06
#define		IP_UDP			0x11

//ICMP
#define		ICMP_PING		0x08
#define		ICMP_PINGREPLY	0x00

class CPacket  
{
public:
    CPacket();
    virtual ~CPacket();

    //初始化
    void InitPacket();
    
    //解析报文
    int Parsepkt(BYTE *pPkt, int nLen); 

    //检测配置选项
    void CheckOption(WORD wProType, BYTE CodeVal, BYTE* pOption);

    //创建PPP报文
    void CreatePPPPkt(WORD wProType, BYTE CodeVal, BYTE* pPkt, bool bActive = FALSE);
    
    //创建IP报文
    void CreateIpPkt(BYTE protocal, BYTE type, BYTE *temp);
 
private:
    //字符编码
    int CharacterEncode(int iLen);

    //转义编码
    int TransferEncode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt);
    //转义解码
    int TransferDecode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt);

    //日志输出
    void WriteLog(CString temp);


public:
	WORD wProtocolType; 		//协议类型 2个字节 
	BYTE PktID;		    		//包 ID 
	BOOL bReject;				//判断包是 ACK     或者 REJ
	BYTE CurState;              //PPP状态
    BYTE SrcIP[4];              //源动态IP
    int nOptionNum;             //配置选项数量
    BYTE PacketTx[256];         //发送包
	BYTE PacketTx1[256];	    //发送包
	BYTE PacketRx[256];         //接受包
	int TxLen;                  //发送包长度
	int RxLen;                  //接受包长度
    BOOL bRecPing;              //是否收到ping回复
	PPP_OPTION_T option[8];     //选项值

	IP_HEADER_T IP_header;
	ICMP_HEADER_T ICMP_header;
    int m_nNcpAckNum;
	
	CCRC m_crc;
};
#endif 

PPP_Packet.cpp

/* ***************************************************************
 * Filename:            Packet.cpp
 *  @Description:
 *         Packet Creat Check
 *  @Author: ybLin
 * ***************************************************************/
#include "stdafx.h"
#include "PPP_Packet.h"
#include "Common.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

int auth_skipped=1;
int block_ipcp_req= 0;

BYTE g_LcpFirstReq[256] = {0x7E, 0xFF, 0x03, 0xC0, 0x21, 0x01, 0x01, 0x00, 0x0A, 0x02, 0x06, 0x00, 0x00, 
                           0x00, 0x00, 0x58, 0x7B, 0x7E};
BYTE g_NcpFirstReq[256] = {0x7E, 0xFF, 0x03, 0x80, 0x21, 0x01, 0x03, 0x00, 0x0A, 0x03, 0x06, 0x00, 
                           0x00, 0x00, 0x00, 0xE9, 0xB3, 0x7E};

BYTE g_TermReq[256] = {0x7E, 0xFF, 0x03, 0xC0, 0x21, 0x05, 0x01, 0x00, 0x04, 0x3D, 0xC7, 0x7E};

char hextbl[] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };

//Common Api
std::string HexToString(const BYTE *pBuffer, size_t iBytes)
{
   std::string result;
   for (size_t i = 0; i < iBytes; i++)
   {
       BYTE c ;
       BYTE b = pBuffer[i] >> 4;

       if (9 >= b)
       {
           c = b + '0';
       }
       else
       {
           c = (b - 10) + 'A';
       }

       result += (TCHAR)c;

       b = pBuffer[i] & 0x0f;

       if (9 >= b)
       {
           c = b + '0';
       }
       else
       {
           c = (b - 10) + 'A';
       }

       result += (TCHAR)c;

       if (i != (iBytes-1))
           result += " ";
   }
   return result;
}

void DectoHex(int dec, char *hex, int length) 
{ 
	for(int i=length-1; i>=0; i--) 
	{ 
		hex[i] = (dec%256)&0xFF; 
		dec /= 256; 
	} 
}

unsigned long HextoDec(const unsigned char *hex, int length) 
{ 
	unsigned long rslt = 0; 
	
	for(int i=0; i<length; i++) 
	{ 
		rslt += (unsigned long)(hex[i])<<(8*(length-1-i)); 
	} 
	
	return rslt; 
} 

CString Ascii2Hex(CString strASCII)
{
	int i;
	int length = strASCII.GetLength();
	CString strHEX;
	CString temp;

	for (i = 0; i < length; i++)
	{
		temp.Format("%2hhX ", strASCII.GetAt(i));// %2hhX 解决出现的FFFFFF问题
		strHEX = strHEX + temp;
	}
	return strHEX;
}

//字符转换为16进制数据
char Char2Hex(char ch)
{

	if ((ch >= '0') && (ch <= '9'))
		return ch - 0x30;
	if ((ch >= 'A') && (ch <= 'F'))
		return ch - 'A' + 10;
	if ((ch >= 'a') && (ch <= 'f'))
		return ch - 'a' + 10;
	else
		return(-1);
}

//字符串转换为16进制数据
int String2Hex(CString str, char* SendOut)
{
	int hexdata, lowhexdata;
	int hexdatalen = 0;
	int len = str.GetLength();

	for (int i = 0; i < len;)
	{
		char lstr, hstr = str[i];
		if (hstr == ' ' || hstr == '\r' || hstr == '\n')
		{
			i++;
			continue;
		}
		i++;
		if (i >= len)
			break;
		lstr = str[i];
		hexdata = Char2Hex(hstr);
		lowhexdata = Char2Hex(lstr);
		if ((hexdata == 16) || (lowhexdata == 16))
			break;
		else
			hexdata = hexdata * 16 + lowhexdata;
		i++;
		SendOut[hexdatalen] = (char)hexdata;
		hexdatalen++;
	}
	return hexdatalen;

}

//Packet
CPacket::CPacket()
{
    InitPacket();
}

CPacket::~CPacket()
{
}

void CPacket::InitPacket()
{
    CurState = PPP_STATE_INIT;
	TxLen = 0;
	bReject = FALSE;
	PktID = 0x01;
    nOptionNum = 0;

	for(int i=0; i<8; i++)
	{
		option[i].bReject = TRUE;
		memset(option[i].bData, 0x0, 64);
	}
	memset(PacketTx,0x0,256);
	memset(SrcIP,0x00,4);
}

int CPacket::Parsepkt(BYTE *pPkt, int nLen)
{
	BYTE CodeVal;
	char tempbuf[100];
    memset(PacketRx, 0x00, 256);
	TxLen = 0;
    int nRet = PPP_OPERATE_NORMAL; 

    if(nLen < MIN_RECV_PKT_SIZE)
    {
        ffprint("nLen < MIN_RECV_PKT_SIZE nLen:%d", nLen);
        nRet = PPP_OPERATE_ERROR;
		return nRet;
    }

    RxLen = TransferDecode(pPkt, nLen, PacketRx);
    if(RxLen < MIN_RECV_PKT_SIZE)
	{
		ffprint("RxLen < MIN_RECV_PKT_SIZE RxLen:%d", RxLen);
        nRet = PPP_OPERATE_ERROR;
		return nRet;
	}

    std::string hexStr2 = HexToString(PacketRx, RxLen);
    ffprint("Parsepkt decode hexStr:%s", hexStr2.c_str());
    

	wProtocolType = PacketRx[3]*256 + PacketRx[4];
 
	switch(wProtocolType)
    {
	    case PROTOCOL_LCP:
		{
			CodeVal = PacketRx[5]; //获取编码值
			PktID = PacketRx[6];
			switch(CodeVal)
            {
    			case PPP_CODE_REQ:

    				CheckOption(wProtocolType, CodeVal, PacketRx);

                    if(bReject == TRUE)
                    {
                        CodeVal = PPP_CODE_REJ;
                    }
                    else 
                    { 
                        CodeVal = PPP_CODE_ACK;
                    }
                
    				CreatePPPPkt(wProtocolType, CodeVal, PacketRx); 	
                    nRet = PPP_OPERATE_NEED_SEND;
    				break;
    			case PPP_CODE_ACK:
                    if(CurState == PPP_STATE_LCP_PASS)
                    {
                        //无认证,直接发送NCP请求
                        CurState = PPP_STATE_NCP_PERIOD;
                        CreatePPPPkt(PROTOCOL_IPCP, PPP_CODE_REQ, g_NcpFirstReq, TRUE);
                        nRet = PPP_OPERATE_NEED_SEND;
                        m_nNcpAckNum = 0;
                    }
    				break;
    			case PPP_CODE_NAK:
    				break;
    			case PPP_CODE_REJ:
    				break;
    			default:
    				break;
			}
			
			break;
		}
	    case PROTOCOL_IPCP:  //无转义
    		CodeVal = PacketRx[5];
    		PktID = PacketRx[6];
    		switch(CodeVal)
            {
        		case PPP_CODE_REQ:
                    ffprint("PROTOCOL_IPCP PPP_CODE_REQ");
                
                    CurState = PPP_STATE_NCP_PERIOD;
        		    CreatePPPPkt(wProtocolType, PPP_CODE_ACK, PacketRx);
                    nRet = PPP_OPERATE_NEED_SEND;
                    m_nNcpAckNum++;
        			break;
        		case PPP_CODE_ACK: //最终受到确认后,NCP通过
                    ffprint("PROTOCOL_IPCP PPP_CODE_ACK");
                
        			if (CurState < PPP_STATE_PPP_PASS)	
                        CurState = PPP_STATE_PPP_PASS;

                    m_nNcpAckNum = 0;

        			break;
        		case PPP_CODE_NAK:
                    ffprint("PROTOCOL_IPCP PPP_CODE_NAK");
                
        			CheckOption(wProtocolType, CodeVal, PacketRx);
                
        			if (CurState < PPP_STATE_NCP_NAK && bReject == false) 
                        CurState = PPP_STATE_NCP_NAK;

        			CreatePPPPkt(wProtocolType, PPP_CODE_REQ, PacketRx);
                    nRet = PPP_OPERATE_NEED_SEND;
        			break;
        		default:
        			break;
    		}
    		break;
/*
    case PAP:
		CodeVal=pPkt[5];
		PktID=pPkt[6];
		switch(CodeVal){
		case REQ:
			break;
		case ACK:

			CurState=PAPPASS;
			memset(PacketTx,0x00,256);
			WriteLog("dingding: after got pap ack from mt, set PAPPASS,then ipcp lcp req to mt");
			makepacket(IPCP,REQ,PacketTx);
			break;
		case NAK:
			break;
		default:
			break;
		}//end switch
		break;//end PAP
*/
    case PROTOCOL_IP:    
		IP_header.protocol = PacketRx[14];
		switch(IP_header.protocol)
		{
    		case IP_ICMP:
    			ICMP_header.type = PacketRx[25];
                ffprint("PROTOCOL_IP protocol:%02x  type:%02x", IP_header.protocol, ICMP_header.type);
    			switch (ICMP_header.type)
    			{
        			case ICMP_PING:
        				//CreateIpPkt(IP_ICMP, ICMP_PINGREPLY, pPkt+5);
        				break;
        			case ICMP_PINGREPLY:
        				bRecPing = true;
        				break;
        			default:
        				break;
    			}
    			break;
    		case IP_UDP:
    			break;
    		default:
    			break;
		}
		break;

	default:
		break;
	}
	return nRet;
}

void CPacket::CheckOption(WORD wProType, BYTE CodeVal, BYTE* pOption)
{
	WORD wSize, wStart;
	int i=0, j=0, k;

	bReject = FALSE;
	wStart = 9; //数据位从这里开始
	wSize = pOption[7]*256 + pOption[8] + 8;            //8:length+framebegin(3)+protocol(2)+checksum(2)+frameend(1)
	if (wSize > MAX_RECV_PKT_SIZE - 8)                  //truncate packet if larger than buffer
        wSize = MAX_RECV_PKT_SIZE - 8;     

    //获取配置项
	for(k=0; k<8; k++)
	{
		option[k].bReject = TRUE;
		memset(option[k].bData, 0x0, 64);
	}

	while(wStart < wSize-3)
	{
		option[j].bType = pOption[wStart++];
		option[j].bLength = pOption[wStart++];
		for (i = 0; i<option[j].bLength-2; i++)
		{
			option[j].bData[i]=pOption[i+wStart];
		}
        
		option[j].bData[i]='\0';
		wStart = i + wStart;
		j++;
	}
	nOptionNum = j;

	switch(wProtocolType)
	{
		case PROTOCOL_LCP:
		{
			for(i=0; i<j; i++)
			{
				if (option[i].bType > 0 && option[i].bType <= 29)
				{
					switch(option[i].bType)
					{
                        //最大-接收-单元
						case 1:		
							option[i].bReject = FALSE;
							break;

                        //异步-控制-字符-映射
						case 2:		
							option[i].bReject = FALSE;
							break;

                        //鉴定-协议
						case 3:		
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;

                        //魔术字
						case 5:		
							option[i].bReject = FALSE;
							break;

                        //协议域压缩
						case 7:		
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;

                        //地址和控制域压缩
						case 8:		
							option[i].bReject = TRUE;
						    bReject = TRUE;
							break;

						default:
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
					}
				}
			}
			break;
		}
		case PROTOCOL_IPCP:
			for(i=0; i<j; i++)
			{
				if ((option[i].bType>0 && option[i].bType<5)||
                    (option[i].bType>=129 && option[i].bType<=132))
				{
					switch(option[i].bType)
					{
						case 1:		                                //静态IP配置
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
						case 2:		                                //IP压缩协议
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
						case 3:		                                //动态IP配置
							option[i].bReject = FALSE;
							if (CodeVal == PPP_CODE_NAK)
							{
								ffprint("NAK option[i].bLength:%d", option[i].bLength);
								for (k=0;k<option[i].bLength-2;k++)
								{
									SrcIP[k] = option[i].bData[k];
                                    ffprint("SrcIP[%d]:%02x", k, SrcIP[k]);
								}
							}
							break;
						default:    
							option[i].bReject = TRUE;
							bReject = TRUE;
							break;
					}
				}
			}
			break;
	}
}

uint16_t crc16_x25(uint8_t *data, int length){
    uint8_t i;
    uint16_t crc = 0xffff;        // Initial value
    while(length--)
    {
        crc ^= *data++;            // crc ^= *data; data++;
        for (i = 0; i < 8; ++i)
        {
            if (crc & 1)
                crc = (crc >> 1) ^ 0x8408;        // 0x8408 = reverse 0x1021
            else
               crc = (crc >> 1);
        }
    }
    return ~crc;                // crc^Xorout
} 


void CPacket::CreatePPPPkt(WORD wProType, BYTE CodeVal, BYTE* pPkt, bool bActive)
{
	int i,j,k;
	WORD wLen, whigh = 0, wlow = 0; //header checksum;
	int iHeadpos;
	WORD wChecksum;
    int nLenthPos;
	
	memset(PacketTx, 0x00, 256);  //有转义的包
	//memset(PacketTx1, 0x00, 256); //无转义的包

	i=0;
	PacketTx[i++] = 0x7e;      //帧首个字节
	switch(wProType)
	{
		case PROTOCOL_LCP:
			switch(CodeVal)
			{
				case PPP_CODE_REQ:
					for(i=1; i<5; i++)
					{
						PacketTx[i] = pPkt[i];                 //frame head and protocol
					}
					
					PacketTx[i++] = CodeVal;                   //code
					PacketTx[i++] = PktID;                     //递增ID
					nLenthPos = i;                             //get the length postion
					i+=2;

                    if(bActive)                                //主动发送,数据域直接拷贝
                    {
                        while(pPkt[i] != 0x7e)                      
    					{
    						PacketTx[i] = pPkt[i];
    						i++;
    					}
    					i-=2;
    					PacketTx[i]='\0';
    					PacketTx[i+1]='\0';
                    }
                    else
                    {
                        //LCP配置项
    					for(k=0; k<nOptionNum; k++)
    					{
    						if(!option[k].bReject)
    						{
    							PacketTx[i++] = option[k].bType;
    							PacketTx[i++] = option[k].bLength;
    							for(j=0; j<option[k].bLength-2; j++)
    								PacketTx[i++] = option[k].bData[j];
    						}
    					}
                    }
                    CurState = PPP_STATE_LCP_PERIOD;
					break;

				case PPP_CODE_ACK:
				{
                    for(i=1; i<5; i++)
					{
						PacketTx[i] = pPkt[i];                  //frame head and protocol
					}
					PacketTx[i++] = CodeVal;                    //code
					int idIndex = i++;
					PacketTx[idIndex] = pPkt[idIndex];          //回复包的ID与请求包的ID一致	

					nLenthPos = i;                              //get the length postion
					i+=2;

					while(pPkt[i] != 0x7e)                      //数据域直接拷贝
					{
						PacketTx[i] = pPkt[i];
						i++;
					}
					i-=2;
					PacketTx[i]='\0';
					PacketTx[i+1]='\0';

                    CurState = PPP_STATE_LCP_PASS;
					break;
                }
                /*
                case PPP_CODE_NAK:
                    for(i=1;i<5;i++)
					{
						PacketTx[i] = pPkt[i];                 //frame head and protocol
					}
                    PacketTx[i++] = CodeVal;                   //code

                    //等做认证才来完善该项
                    
                    break;*/
                    
                case PPP_CODE_REJ:
                    for(i=1; i<5; i++)
					{
						PacketTx[i] = pPkt[i];                 //frame head and protocol
					}
					
					PacketTx[i++] = CodeVal;                   //code
					PacketTx[i++] = PktID;                     //递增ID
					nLenthPos = i;                             //get the length postion
					i+=2;                           

                                                                
					for(k=0; k<nOptionNum; k++)                //LCP配置项 添加拒绝的配置项
					{
						if(option[k].bReject)
						{
							PacketTx[i++] = option[k].bType;
							PacketTx[i++] = option[k].bLength;
							for(j=0; j<option[k].bLength-2; j++)
								PacketTx[i++]=option[k].bData[j];
						}
					}
                    CurState = PPP_STATE_LCP_PERIOD;
                    break;

                case PPP_CODE_TERM_LINK:
                {
                    for(i=1; i<5; i++)
					{
						PacketTx[i] = pPkt[i];                  //frame head and protocol
					}
					PacketTx[i++] = CodeVal;                    //code
					PacketTx[i++] = PktID;                     //递增ID

					nLenthPos = i;                              //get the length postion
					i+=2;

					while(pPkt[i] != 0x7e)                      //数据域直接拷贝
					{
						PacketTx[i] = pPkt[i];
						i++;
					}
					i-=2;
					PacketTx[i]='\0';
					PacketTx[i+1]='\0';

                    CurState = PPP_STATE_TERM_LINK;
                    break;
                }      
			}
			break;
/*			
		case PAP:
			PacketTx[i++]=0xff;
			PacketTx[i++]=0x03;
			PacketTx[i++]=0xc0;
			PacketTx[i++]=0x23;
			PacketTx[i++]=CodeVal;
			PacketTx[i++]=PktID;
			nLenthPos=i;
			i+=2;
			PacketTx[i++]=0x06;
			PacketTx[i++]='1';
			PacketTx[i++]='6';
			PacketTx[i++]='3';
			PacketTx[i++]=0x08;
			PacketTx[i++]='1';
			PacketTx[i++]='6';
			PacketTx[i++]='3';
			break;
*/
		case PROTOCOL_IPCP:
            switch(CodeVal)
            {
                case PPP_CODE_REQ:
                {
                    for(i=1;i<5;i++)
        		    {
        			     PacketTx[i] = pPkt[i];                 //frame head and protocol
        		    }
					
                    PacketTx[i++] = 0x01;                       //code
                    PacketTx[i++] = PktID++;                    //id 
                    nLenthPos = i;                              //get the length postion
                    i += 2;

                    if(bActive)                                //主动发送,数据域直接拷贝
                    {
                        while(pPkt[i] != 0x7e)                      
    					{
    						PacketTx[i] = pPkt[i];
    						i++;
    					}
    					i-=2;
    					PacketTx[i] = 0x00;
    					PacketTx[i+1] = 0x00;
                    }
                    else
                    {
                        if(CurState == PPP_STATE_NCP_NAK)
                        {
                            PacketTx[i++] = 0x03;
    						PacketTx[i++] = 0x06;
                    
                            ffprint("IPCP PPP_CODE_REQ nOptionNum:%d", nOptionNum);
                            for(k=0; k<nOptionNum; k++) 
                            {
                                if(!option[k].bReject)
                                {
                                    for(j=0;j<option[k].bLength-2;j++)
            						{
            							//ffprint("NAK SrcIP[%d]:%02x", j, SrcIP[j]);
        								PacketTx[i++] = SrcIP[j];
        							} 
                                }
                            }
                        }
                    }
                    
                    break;
                }   
                case PPP_CODE_ACK:
                {
                    for(i=1;i<5;i++)
        		    {
        			     PacketTx[i] = pPkt[i];                //frame head and protocol
        		    }
                    PacketTx[i++] = 0x02;                   //code
                    int idIndex = i++;
					PacketTx[idIndex] = pPkt[idIndex];         //回复包的ID与请求包的ID一致	
                    
                    nLenthPos = i;                             //get the length postion
					i+=2;
					while(pPkt[i] != 0x7e)                     //数据域直接拷贝
					{
						PacketTx[i] = pPkt[i];
						i++;
					}
					i-=2;
					PacketTx[i]=0x00;
					PacketTx[i+1]=0x00; 
                    break;
                }
                case PPP_CODE_NAK:
                    break;
                case PPP_CODE_REJ:
                    break;
                default:
                    break;

            }
        
			break;

		default:
			break;
	}

	wLen = i-5;    
    if(wProType == PROTOCOL_LCP)
    {
        PacketTx[nLenthPos++] = wLen/256;
	    PacketTx[nLenthPos] = wLen%256;
    }
    else
    {
        char Hight[2];
        char Low[2];


        DectoHex((int)(wLen/256), Hight, 1);
        DectoHex((int)(wLen%256), Low, 1);

        PacketTx[nLenthPos++] = (BYTE)Hight[0];
        PacketTx[nLenthPos++] = (BYTE)Low[0];

        ffprint("wLen:%d Hight:%02x, Low:%02x", wLen, Hight[0], Low[0]);
    }

	//CRC校验
    //CString strText;
    //strText.Format(_T("校验:%s"), HexToString(PacketTx+1, i-1));
    //ffprint("strText:%s", strText);

	wChecksum = m_crc.CountCRC(PacketTx+1, i-1);//get checksum and copy to szPacketTx[crcpos]
    //wChecksum=m_crc.CountCRC(TestByte, 14);

	//2.
/*
    wChecksum=crc16_x25(PacketTx+1, i-1);
    ffprint("x1:%x", wChecksum & 0x00ff);
    ffprint("x2:%x", (wChecksum>>8) & 0x00ff);
*/    
    
	PacketTx[i++]=(wChecksum & 0x00ff);
	PacketTx[i++]=((wChecksum>>8) & 0x00ff);

    if(wProType == PROTOCOL_LCP)
    {
        i = CharacterEncode(i);
    }
    
    PacketTx[i] = 0x7e;//and framing end 0x7e
	TxLen = i+1;
	PktID++;
	bReject = FALSE;
}

void CPacket::CreateIpPkt(BYTE protocal, BYTE type, BYTE *temp)
{
	int i,j,k;
    int nLenthPos, nHeadcheckpos, nIcmpcheckpos;
	WORD wLen,whigh = 0x0000,wlow = 0x0000;//header checksum;
	int iHeadpos,TTLpos;
	WORD wChecksum;
	
	memset(PacketTx, 0x00, 256);

    //7E FF 03 00 21
	i = 0;
	PacketTx[i++] = 0x7e;//frame header

	PacketTx[i++] = 0xff;
	PacketTx[i++] = 0x03;

    PacketTx[i++] = 0x00;
	PacketTx[i++] = 0x21;
	iHeadpos = i;

    //版本(4) + 首部长度(4) + 区分服务(8)
	PacketTx[i++] = 0x45;   //version and header length
	PacketTx[i++] = 0x00;   //service

    //总长度
	nLenthPos = i;			//total length position
	i += 2;

    //标识
    PacketTx[i++] = 0x00;
    PacketTx[i++] = 0x05;

    //标志(8) + 片偏移(8)
    PacketTx[i++]=0x00;
	PacketTx[i++]=0x00;

    //生存时间(8) + 协议(8)
	TTLpos=i;
	PacketTx[i++] = 0x80;//TTL
	PacketTx[i++] = protocal;//0x11:UDP 0x01:ICMP

    //IP 首部校验和
	nHeadcheckpos=i;
	PacketTx[i++]=0x00;//header checksum
	PacketTx[i++]=0x00;//header checksum

    //源IP
	for(j=0;j<4;j++)
	{
		PacketTx[i++]=SrcIP[j];//source ip address
	}

	switch(protocal)
	{
   
	case IP_ICMP:
		switch(type)
		{
		case ICMP_PING:

			//目标IP地址
			for(j=0; j<4; j++)
			{
				PacketTx[i++] = temp[j];
			}
		
			//类型 8位 ICMP type 0x08:请求 0x00:回复
			PacketTx[i++] = type;  

			//code 8位
			PacketTx[i++] = 0x00;//ICMP code

			//ICMP校验位和 16位
			nIcmpcheckpos = i;				
			PacketTx[i++] = 0x00;//icmp checksum set 0
			PacketTx[i++] = 0x00;//icmp checksum set 0

			//ICMP id 16位 ping进程的进程号
			PacketTx[i++] = 0x00;
			PacketTx[i++] = 0x01;

			//每个发送出去的分组递增序列号
			PacketTx[i++] = ICMP_header.sequence & 0x00ff;	//sequence number lsb
			PacketTx[i++] = ICMP_header.sequence >> 8;		//sequence number msb
			ICMP_header.sequence++;

			//数据部分
			k = temp[4]*256+temp[5];
			for (j=0; j<k; j++)
			{
				PacketTx[i++] = temp[6+j];
			}

			break;    
        /*
		case ICMP_PINGREPLY:
			PacketTx[TTLpos]=temp[8]-1;
			for(j=0;j<4;j++)
			{
				PacketTx[i++]=temp[j+12];       //destination ip address
			}
			PacketTx[i++]=type;	                //ICMP type ???????
			PacketTx[i++]=00;		            //ICMP code
			nIcmpcheckpos=i;				
			PacketTx[i++]=0x00;	                //icmp checksum set 0
			PacketTx[i++]=0x00;	                //icmp checksum set 0
			PacketTx[i++]=temp[24];
			PacketTx[i++]=temp[25];
			PacketTx[i++]=temp[26];	            //reply the same sequence number
			PacketTx[i++]=temp[27];	            //reply the same sequence number

			int jj,kk;
			kk=0;
			kk+=temp[2]*256+temp[3];
			jj=28;
			for (;jj<kk;) 
				PacketTx[i++]=temp[jj++];	//copy the last data
			break;*/
		default:
			break;
		}

        //ICMP 校验和计算
		wlow = 0;
		whigh = 0;
		for(j=nIcmpcheckpos-2; j<i; j+=2)
		{
			whigh += PacketTx[j];
		}
		for(j=nIcmpcheckpos-1; j<i; j+=2)
		{
			wlow += PacketTx[j];
		}

		//write the sub header checksum
		wlow += whigh/256;
		whigh = (whigh & 255)+wlow/256;
		wlow = (wlow & 255)+whigh/256;	
		whigh = ~whigh;
		wlow = ~wlow;
		PacketTx[nIcmpcheckpos++] = (whigh & 0x00ff);
		PacketTx[nIcmpcheckpos] = (wlow & 0x00ff);

		break;
		
	case IP_UDP:

        //目标IP + 源端口 + 目标端口 + 长度
		for(j=0; j<10; j++)
		{
			PacketTx[i++] = temp[j];
		}
    
        //UDP校验和
		nIcmpcheckpos = i;
		PacketTx[i++] = 0x00;
		PacketTx[i++] = 0x00;

        //UDP 发送的数据
		k = temp[8]*256+temp[9]+4;
		for(j=12;j<k;j++)
		{
			PacketTx[i++]=temp[j];
		}

        //计算UDP校验和
		wlow = 0x0000;
		whigh = 0x0000;
		for(j=nIcmpcheckpos-14; j<i; j+=2)
		{
			whigh += PacketTx[j];
		}
		for(j=nIcmpcheckpos-13; j<i; j+=2)
		{
			wlow += PacketTx[j];
		}
		whigh += temp[8];
		wlow += 0x11;
		wlow += temp[9];


		//write the sub header checksum
		wlow += whigh/256;
		whigh = (whigh & 255)+wlow/256;
		wlow = (wlow & 255)+whigh/256;	
		whigh = ~whigh;
		wlow = ~wlow;
		PacketTx[nIcmpcheckpos++] = (whigh & 0x00ff);
		PacketTx[nIcmpcheckpos] = (wlow & 0x00ff);


	default:
		break;
	}    
	wLen=i-5;
	PacketTx[nLenthPos++]=wLen/256;
	PacketTx[nLenthPos]=wLen%256;

	
	//计算IP校验和
	wlow=0;
	whigh=0;
	for(j=iHeadpos; j<20+iHeadpos; j+=2)
	{
		whigh += PacketTx[j];
	}
	for(j=iHeadpos+1; j<=20+iHeadpos; j+=2)
	{
		wlow += PacketTx[j];
	}
	wlow += whigh/256;
	whigh = (whigh & 255)+wlow/256;
	wlow = (wlow & 255)+whigh/256;
	whigh = ~whigh;
	wlow = ~wlow;
	PacketTx[nHeadcheckpos++] = (whigh & 0x00ff);
	PacketTx[nHeadcheckpos] = (wlow & 0x00ff);

    //计算CRC校验
	wChecksum = m_crc.CountCRC(PacketTx+1,i-1);//get checksum and copy to szPacketTx[crcpos]
	PacketTx[i++] = (wChecksum & 0x00ff);
	PacketTx[i++] = ((wChecksum>>8) & 0x00ff);

	PacketTx[i] = 0x7e;
	TxLen = i+1;
	PktID++;
	bReject = FALSE;
}

int CPacket::CharacterEncode(int iLen)
{
	BYTE temp,endtemp;
	int i,j;

	for(i=1;i<iLen;i++)
	{
		if(PacketTx[i]>=0x00 && PacketTx[i]<0x20)
		{
			endtemp=PacketTx[iLen++];
			for(j=iLen-1;j>i;j--)
			{
				temp=PacketTx[j];
				PacketTx[j+1]=temp;
			}
			temp=PacketTx[i]+0x20;
			PacketTx[i++]=0x7d;
			PacketTx[i]=temp;
			PacketTx[iLen]=endtemp;
		}
		else if(PacketTx[i]==0x7d)
		{
			endtemp=PacketTx[iLen++];
			for(j=iLen-1;j>i;j--)
			{
				temp=PacketTx[j];
				PacketTx[j+1]=temp;
			}
			temp=0x5d;
			PacketTx[i++]=0x7d;
			PacketTx[i]=temp;
			PacketTx[iLen]=endtemp;
		}
		else if(PacketTx[i]==0x7e)
		{
			endtemp=PacketTx[iLen++];
			for(j=iLen-1;j>i;j--)
			{
				temp=PacketTx[j];
				PacketTx[j+1]=temp;
			}
			temp=0x5e;
			PacketTx[i++]=0x7d;
			PacketTx[i]=temp;
			PacketTx[iLen]=endtemp;
		}
	}
	return(iLen);
}

int CPacket::TransferEncode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt)
{
    unsigned char *pIn, *pOut;
    int i, nTmpLen;
    
    pIn = pInPkt;
    pOut = pOutPkt;
    nTmpLen = nInLen;
	int nOutLen = 0;
    
    for(i = 0; i < nInLen; i++)
    {
        if(*pIn == PPP_FRAME_FLAG || *pIn == PPP_FRAME_ESC || *pIn < 0x20)
        {
            *pOut = PPP_FRAME_ESC;
            pOut++;
            nTmpLen++;    
            *pOut = *pIn ^ PPP_FRAME_ENC;
        }
        else
        {
            *pOut = *pIn;    
        }
        
        pIn++;
        pOut++;
    }
    nOutLen = nTmpLen;
    
    return nOutLen;    
}

int CPacket::TransferDecode(unsigned char *pInPkt, int nInLen, unsigned char *pOutPkt)
{
    unsigned char *pIn, *pOut;
    int i, nTmpLen;
    
    pIn = pInPkt;
    pOut = pOutPkt;
    nTmpLen = nInLen;
	int nOutLen = 0;
     
   	for(i = 0; i < nInLen; i++)
    {
        if(*pIn == PPP_FRAME_ESC)
        {
            pIn++;
           	nTmpLen--;
            *pOut = *pIn ^ PPP_FRAME_ENC;
            
            i++;
        }    
        else
        {
            *pOut = *pIn;    
        }
        
        pIn++;
        pOut++;
    }
    nOutLen = nTmpLen;
    
    return nOutLen;
}

void CPacket::WriteLog(CString temp)
{
	CStdioFile file;
	CString filename;
	CTime time;
	time = CTime::GetCurrentTime();
	filename = time.Format("%Y%m%d");
	file.Open(filename+".log",CFile::modeNoTruncate|CFile::modeCreate|CFile::modeWrite|CFile::typeText);
	file.SeekToEnd();
	temp = time.Format("%Y.%m.%d %H:%M:%S  ")+temp+"\r\n";
	file.Write(temp,temp.GetLength());
	file.Close();
}

4. Related document download:

https://download.csdn.net/download/linyibin_123/87759183

Guess you like

Origin blog.csdn.net/linyibin_123/article/details/130522062
ppp