📄 dhcp.c
字号:
/*
*****************************************************************************************************
*
* File name: dhcp.c
*****************************************************************************************************
*/
#include "..\head\includes.h"
void DHCP_Pack(unsigned char PACK_TYPE) ;
/*
*****************************************************************************************************
*FUNC: DHCP解析
*NOTE:
*****************************************************************************************************
*/
//******* DHCP 的6种状态 *******
#define DHCP_INIT 0
#define DHCP_SELECT 1
#define DHCP_REQUEST 2
#define DHCP_BOUND 3
#define DHCP_RENEW 4
#define DHCP_REBIND 5
//******* DHCP 的几种报文类型状态 *******
#define OP_DHCPDISCOVER 1
#define OP_DHCPOFFER 2
#define OP_DHCPREQUEST 3
#define OP_DHCPDELINE 4
#define OP_DHCPACK 5
#define OP_DHCPNACK 6
#define OP_DHCPRELEASE 7
#define OP_DHCPINFORM 8
_DHCP_REG_ xdata DHCPReg;
bit bBound = FALSE;
/*
*****************************************************************************************************
*FUNC: 绑定与释放回调函数
*NOTE:
*****************************************************************************************************
*/
void On_Bound(void) reentrant
{
//申请到的IP可写入FLASH,下次开机时优先申请该IP.可选做
DHCPReg.timer100.dwords = 60; //2分钟 FOR DEBUG
if ((DHCPReg.timer100.dwords == 0) || (DHCPReg.timer100.dwords > 7200)){
DHCPReg.timer100.dwords = 7200; //如果DHCP没指配时间或大于2小时,默认为2小时
}
my_ip_address.dwords = DHCPReg.myip.dwords; //使用分配得到的IP
gateway_ip_address.dwords = DHCPReg.gatewayip.dwords; //使用分配得到的网关IP
mask_ip_address.dwords = DHCPReg.maskip.dwords; //使用分配得到的子网掩码
if (gateway_ip_address.dwords == 0) { //网关IP=0
if (DHCPReg.severip.dwords != 0) { //DHCP服务器IP不等于0
gateway_ip_address.dwords = DHCPReg.severip.dwords;//把DHCP服务器IP当作网关IP
}
}
DHCPReg.timer50.dwords = (DHCPReg.timer100.dwords) / 2; //50%定时器
DHCPReg.timer87.dwords = DHCPReg.timer100.dwords * 875 /1000; //87.5%定时器
bBound = TRUE;
}
void On_Release(void)reentrant
{
DHCP_Pack(OP_DHCPRELEASE);
bBound = FALSE;
DHCPReg.state = DHCP_INIT;
if (bConnect) { //如果已连上,关闭链路
tcp_send(&TCPSend,FLG_RST, 20, IndexOfClient); //这里一定要加RST
InerClose(IndexOfClient); //关闭该套接字,重连
}
}
/*
*****************************************************************************************************
*FUNC: DHCP 初始化
*NOTE:
*****************************************************************************************************
*/
void DHCPValueInit(void)
{
bBound = FALSE;
DHCPReg.state = DHCP_INIT;
DHCPReg.myip.dwords = 0;
DHCPReg.gatewayip.dwords = 0;
DHCPReg.maskip.dwords = 0;
DHCPReg.dns_m.dwords = 0;
DHCPReg.dns_s.dwords = 0;
DHCPReg.severip.dwords = 0;
DHCPReg.timer100.dwords = 0;
DHCPReg.timer50.dwords = 0;
DHCPReg.timer87.dwords = 0;
}
void DHCPInit(void)
{
DHCPValueInit();
DHCPReg.on_bound = (void*)On_Bound;
DHCPReg.on_release = (void*)On_Release;
}
/*
*****************************************************************************************************
*FUNC: 打包 DHCP Discover
*NOTE: 1: DHCP 是基于UDP协议的
2: 果没回应隔9,13,16秒后再发,如果还是没响应,隔5分钟分钟再发起DISCOVER
3: UDP CRC包括UDP头及UDP数据 长度len
全部广播在家里路由器试可以续租可以得到响应
//my_ip_address.dwords = 0;//自己的IP还是未知发0.0.0.0
//DHCP_Pack_Send(pTxdnet, dest_ip, UDP_TYPE, len);
*****************************************************************************************************
*/
void DHCP_Pack(unsigned char PACK_TYPE)
{
unsigned int len,i;
unsigned char model_id_len=0,j;
union netcard xdata *pTxdnet;
union IP_address xdata dest_ip;
union IP_address xdata source_ip;
pTxdnet = &UDPSend;
source_ip.dwords = 0; //源IP未知,发送0.0.0.0
dest_ip.dwords = 0xffffffff; //目的IP未知,采用广播
pTxdnet->udpframe.sourceport = 68; //DHCP源端口为68
pTxdnet->udpframe.destport = 67; //DHCP目的端口为67
//pTxdnet->udpframe.length = len; //长度未定
pTxdnet->udpframe.crc = 0; //UDP头部8字节
pTxdnet->ipframe.sourceip[0] = source_ip.words[0]; //参于计算检验和,不算在UDP长度里
pTxdnet->ipframe.sourceip[1] = source_ip.words[1]; //源IP未知,发送0.0.0.0
pTxdnet->ipframe.destip[0] = dest_ip.words[0];
pTxdnet->ipframe.destip[1] = dest_ip.words[1]; // ffffffff
pTxdnet->dhcpframe.op = 1; //DHCP 请求
pTxdnet->dhcpframe.hardwaretype = 1; //以太网
pTxdnet->dhcpframe.hardwarelen = 6;
pTxdnet->dhcpframe.hops = 0; //跳数置0
pTxdnet->dhcpframe.transactionid = DHCPReg.transactionid; //类似SEQ
pTxdnet->dhcpframe.seconds = 500; //?
pTxdnet->dhcpframe.flags = 0x8000; //最高位为1:广播请求,0:单播 抓包=0
for (i=0; i<4; i++) {
if ((PACK_TYPE == OP_DHCPREQUEST) && bBound){ //续租的时候这里要填之前申请到的本地IP
pTxdnet->dhcpframe.clientip[i] = DHCPReg.myip.bytes[i];
} else {
pTxdnet->dhcpframe.clientip[i] = 0; //参照抓包也是=0
}
pTxdnet->dhcpframe.yourip[i] = 0; //DHCP服务器分配给客户端的
pTxdnet->dhcpframe.severip[i] = 0; //如果须要转发才填
pTxdnet->dhcpframe.gatewayip[i] = 0; //如果须要转发才填
}
for (i=0; i<16; i++) { //16字节前6字节填客户硬件地址,余补0
if (i < 6) {
pTxdnet->dhcpframe.clientmac[i] = my_ethernet_address.bytes[i];
} else {
pTxdnet->dhcpframe.clientmac[i] = 0;
}
}
for (i=0; i<64; i++) { //服务器主机名Server之名称字串,以0x00结尾
pTxdnet->dhcpframe.severhostname[i] = 0;
}
for (i=0; i<128; i++) { //启动文件名若client需要透过网路开机
pTxdnet->dhcpframe.bootfilename[i] = 0;
}
pTxdnet->dhcpframe.magic[0]=0x63; //抓包这里有四字节内容如右:(OK)
pTxdnet->dhcpframe.magic[1]=0x82;
pTxdnet->dhcpframe.magic[2]=0x53;
pTxdnet->dhcpframe.magic[3]=0x63;
//len = 8+28+16+64+128+4;
len = 248; //长度很重要
//---------- 以下为OPTIONS --------------------
i=0; //长度可变
//----- 包类型 -----------
pTxdnet->dhcpframe.options[i++]=53; //选项代码
pTxdnet->dhcpframe.options[i++]=1; //选项长度
pTxdnet->dhcpframe.options[i++]=PACK_TYPE; //DHCP包类型
//----- 请求自动分配 ------
if (PACK_TYPE == OP_DHCPDISCOVER) { //发现包时请求自动分配
pTxdnet->dhcpframe.options[i++]=0x74;
pTxdnet->dhcpframe.options[i++]=1;
pTxdnet->dhcpframe.options[i++]=1;
}
//----- 请求使用该本地IP ------
if ((PACK_TYPE == OP_DHCPREQUEST) && (bBound==FALSE)){ //DHCP offer后有分配给一个本地IP
pTxdnet->dhcpframe.options[i++]=50; //请求本地IP填在选项里
pTxdnet->dhcpframe.options[i++]=4;
pTxdnet->dhcpframe.options[i++]=DHCPReg.myip.bytes[0];
pTxdnet->dhcpframe.options[i++]=DHCPReg.myip.bytes[1];
pTxdnet->dhcpframe.options[i++]=DHCPReg.myip.bytes[2];
pTxdnet->dhcpframe.options[i++]=DHCPReg.myip.bytes[3];
//DHCP SEVER IP填在选项里
pTxdnet->dhcpframe.options[i++]=54;
pTxdnet->dhcpframe.options[i++]=4;
pTxdnet->dhcpframe.options[i++]=DHCPReg.severip.bytes[0];
pTxdnet->dhcpframe.options[i++]=DHCPReg.severip.bytes[1];
pTxdnet->dhcpframe.options[i++]=DHCPReg.severip.bytes[2];
pTxdnet->dhcpframe.options[i++]=DHCPReg.severip.bytes[3];
}
//----- 主动释放时如果有本地IP,选填 ------
if ((PACK_TYPE == OP_DHCPRELEASE) && (bBound == TRUE)) {
pTxdnet->dhcpframe.options[i++]=50; //请求本地IP填在选项里
pTxdnet->dhcpframe.options[i++]=4;
pTxdnet->dhcpframe.options[i++]=DHCPReg.myip.bytes[0];
pTxdnet->dhcpframe.options[i++]=DHCPReg.myip.bytes[1];
pTxdnet->dhcpframe.options[i++]=DHCPReg.myip.bytes[2];
pTxdnet->dhcpframe.options[i++]=DHCPReg.myip.bytes[3];
}
//----- host name(用ID代替) ------
model_id_len = strlen(ModelIdBak);
pTxdnet->dhcpframe.options[i++] = 12;
pTxdnet->dhcpframe.options[i++] = model_id_len;
for (j=0; j<model_id_len; j++) { //ID的字符串
pTxdnet->dhcpframe.options[i++] = ModelIdBak[j];
}
if (PACK_TYPE == OP_DHCPREQUEST) {
pTxdnet->dhcpframe.options[i++]=81;
pTxdnet->dhcpframe.options[i++]=4+model_id_len;
pTxdnet->dhcpframe.options[i++]=0;
pTxdnet->dhcpframe.options[i++]=0;
pTxdnet->dhcpframe.options[i++]=0;
for (j=0; j<model_id_len; j++) { //ID的字符串
pTxdnet->dhcpframe.options[i++] = ModelIdBak[j];
}
pTxdnet->dhcpframe.options[i++]=0x2e;
}
//----- vendor class ------
pTxdnet->dhcpframe.options[i++]=60;
pTxdnet->dhcpframe.options[i++]=8;
pTxdnet->dhcpframe.options[i++]=0x4d;
pTxdnet->dhcpframe.options[i++]=0x53;
pTxdnet->dhcpframe.options[i++]=0x46;
pTxdnet->dhcpframe.options[i++]=0x54;
pTxdnet->dhcpframe.options[i++]=0x20;
pTxdnet->dhcpframe.options[i++]=0x35;
pTxdnet->dhcpframe.options[i++]=0x2e;
pTxdnet->dhcpframe.options[i++]=0x30;
pTxdnet->dhcpframe.options[i++]=255; //DHCP包结束
len+=i; //+选项长度很重要
pTxdnet->udpframe.length = len; //UDP长度头+数据
createudpcrc(pTxdnet,len); //CRC包括UDP头及UDP数据
//===================以上打包===============================
//构建以太网包
pTxdnet->etherframe.protocal=0x0800;
pTxdnet->etherframe.uSourceID[0]=my_ethernet_address.words[0]; //网卡地址
pTxdnet->etherframe.uSourceID[1]=my_ethernet_address.words[1];
pTxdnet->etherframe.uSourceID[2]=my_ethernet_address.words[2];
pTxdnet->ipframe.verandihl=0x45;
pTxdnet->ipframe.typeofserver=0x00;
pTxdnet->ipframe.totallength=20+len;
pTxdnet->ipframe.ttl=0x80;
pTxdnet->ipframe.frameindex=frameindex;
frameindex++;
pTxdnet->ipframe.segment=0x0000;
pTxdnet->ipframe.protocal=UDP_TYPE; //基于UDP协议
pTxdnet->ipframe.crc=0;
pTxdnet->ipframe.destip[0]=dest_ip.words[0]; //填全1
pTxdnet->ipframe.destip[1]=dest_ip.words[1];
pTxdnet->ipframe.sourceip[0]=source_ip.words[0]; //填全0
pTxdnet->ipframe.sourceip[1]=source_ip.words[1];
pTxdnet->ipframe.crc=createipheadcrc(pTxdnet);
pTxdnet->etherframe.uDestID[0]=0xffff; //填写目的MAC,采用广播
pTxdnet->etherframe.uDestID[1]=0xffff;
pTxdnet->etherframe.uDestID[2]=0xffff;
send_packet(pTxdnet,34+len);
}
/*
*****************************************************************************************************
*FUNC: 如果一直没分配到IP,2s 请求一次
*NOTE:
1:封装发送广播一个DHCPDISCOVER(DHCP发现)包,目的端口填67,
2:进入SELECT状态
*****************************************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -