⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dhcp.c

📁 本程序是一个RS232转网口的。是一个透明传输的模块
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
*****************************************************************************************************
*
*  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 + -