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

📄 dhcp.c

📁 本程序是一个RS232转网口的。是一个透明传输的模块
💻 C
📖 第 1 页 / 共 2 页
字号:
*/
void DHCPRequest(void)
{
    if (ModelStatu == MODEL_CONFIG_STATU) {        //配置状态下不去连接服务器
        return;
	}

    DHCPValueInit();                              //变量及各IP地址初始化

	EA = 0;
	DHCPReg.transactionid = initial_sequence_nr;  //我的交互ID 
	initial_sequence_nr += 64000L;
	EA = 1;

	DebugMsg(60);
    DHCP_Pack(OP_DHCPDISCOVER);        // 封装发送广播一个DHCPDISCOVER(DHCP发现)包,目的端口填67,        
	DHCPReg.state = DHCP_SELECT;       //进入SELECT状态
}


/*
*****************************************************************************************************
*FUNC:   响应码查询是不是想要的信息
*NOTE: 
*****************************************************************************************************
*/
//******* DHCP 响应选项中可能包含的信息代码 *******
#define DHCP_OPCODE_NUM  5
unsigned char code  DHCP_Opcode_Table[DHCP_OPCODE_NUM]=
{
    1,    //0:子网掩码
    3,    //1:路由IP地址
	51,   //2:租期时间
    6,    //3:DNS服务器的IP,有可能是这样的:6 08 0 1 2 3 4 5 6 7  //8字节IP为主副DNS IP  
	54    //4:服务器ip,指DHCP服务器
}; 


//******* 对应上面的表 *******
#define OP_CODE_MASKIP    0   //子网掩码
#define OP_CODE_ROUTERS   1   //路由器IP
#define OP_CODE_USETIME   2   //租期时间
#define OP_CODE_DNS       3   //DNS服务器IP
#define OP_CODE_SEVERIP   4   //服务器IP

bit Find_Opcode_Table(unsigned char op_code,unsigned char *op_type)
{
    unsigned char i;

	for (i=0; i<DHCP_OPCODE_NUM; i++) {
        if (op_code == DHCP_Opcode_Table[i]) {
		    *op_type = i;
            return TRUE;
		}
	}
	return FALSE;
}


/*
*****************************************************************************************************
*FUNC: 解析接收到的 DHCP 侦里的各信息
*NOTE: 
*****************************************************************************************************
*/
#define OPTIONS_IP  255 
bit ParseOptions(unsigned char len,unsigned char type,
                 unsigned char xdata *psource,unsigned char xdata *pdest)
{
    unsigned char i;
    
    if (len != 4) {                                    //IP长度不能超过4
        return FALSE;
	}
	
    for (i=0; i<4; i++) {
        *pdest = *psource++;
		if ((type == OPTIONS_IP) && (*pdest > 255)) {   //IP不能大于255
            return FALSE;
	    }
        pdest++;
	}
    return TRUE;
}


/*
*****************************************************************************************************
*FUNC: 解析接收到的 DHCP 侦
*NOTE: dhcp_len为DHCP包的长度不包含UDP头的8字节

    #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
*****************************************************************************************************
*/
void ParseRxdDHCP(union netcard xdata *pRxdnet,unsigned int dhcp_len)
{
    unsigned int  options_len=0;   //选项长度,因其是可变长的
	unsigned int  i;
	unsigned char op_code;         //项目代码 如53表示是包类型
    unsigned char op_len;          //项目代码 对应的包长度
	unsigned char op_type;         //项目类型: 3为路由;1:子网掩码.....
	unsigned char pack_type;       //包类型,8种状态.

    if (pRxdnet->dhcpframe.op != 2) {                                //1:请求, 2:应答
        return;
	}
    if (pRxdnet->dhcpframe.transactionid != DHCPReg.transactionid) { //不是对应的包
        return;
	}

    for (i=0; i<6; i++) {                                     //16字节前6字节填是客户硬件地址
        if (pRxdnet->dhcpframe.clientmac[i] != my_ethernet_address.bytes[i]){
		    return;                                           //判断网卡地址是不是我的
		}
	}
	
	if (dhcp_len < 240) {                                     //236为DHCP封装包OPTIONS前所有的长度
        return;
	}
	options_len = dhcp_len-240;                               //还要减去4字节的(OK)

    /*  
    //观察续租返回包
    if ((DHCPReg.state == DHCP_RENEW ) || (DHCPReg.state == DHCP_REBIND))  {
		Uart0Putsl(pRxdnet->dhcpframe.options,options_len);
	}
	*/
                    	
    if (pRxdnet->dhcpframe.options[0] != 53) {                //包类型
        return;
	} else {
	    op_code   = 53;
	    op_len    = pRxdnet->dhcpframe.options[1];
        pack_type = pRxdnet->dhcpframe.options[2];
	}

	if (pack_type > 8) {                                      //DHCP 报文类型只有8种          
        return;
	}

	if ((pack_type == OP_DHCPACK) || (pack_type == OP_DHCPOFFER)) {   //是分配IP的应答包,此时OPTIONS里有想要的IP信息,做解析 
        if (ParseOptions(4,OPTIONS_IP,pRxdnet->dhcpframe.yourip,DHCPReg.myip.bytes) == FALSE) {
            return;
		} 
        for (i=3; i<options_len; ) {                     //i=3是去掉包类型,长度,码值3字节,
            op_code = pRxdnet->dhcpframe.options[i++];   //码
			if (op_code == 0xff) {                       //结束符 
                break;
			}
            op_len  = pRxdnet->dhcpframe.options[i++];   //长度
			if (Find_Opcode_Table(op_code,&op_type)) {   //内容,查找是不是我们希望要的码
                switch (op_type) {                       //得到码类型
                    case OP_CODE_MASKIP:                 //子网掩码解析
                         if (ParseOptions(op_len,OPTIONS_IP,&(pRxdnet->dhcpframe.options[i]),DHCPReg.maskip.bytes) == FALSE) {
                             return;
		                 }
					     break;
                    case OP_CODE_ROUTERS:                //路由器IP解析
						 if (ParseOptions(op_len,OPTIONS_IP,&(pRxdnet->dhcpframe.options[i]),DHCPReg.gatewayip.bytes) == FALSE) {
                             return;
		                 }
					     break;
                    case OP_CODE_USETIME:                //租期时间解析
                         if (ParseOptions(op_len,0,&(pRxdnet->dhcpframe.options[i]),DHCPReg.timer100.bytes) == FALSE) {
                             return;
		                 }
					     break;
                    case OP_CODE_DNS:                   //DNS服务器IP解析,如果8字节为主副DNS IP
					     if ((op_len != 8) && (op_len != 4)) {
                             return;
						 }
						 if (op_len == 8) {             //分2次主副
						     op_len = 4;
                             if (ParseOptions(op_len,OPTIONS_IP,&(pRxdnet->dhcpframe.options[i+4]),DHCPReg.dns_s.bytes) == FALSE) {
                                 return;
		                     }
						 }
                         if (ParseOptions(op_len,OPTIONS_IP,&(pRxdnet->dhcpframe.options[i]),DHCPReg.dns_m.bytes) == FALSE) {
                             return;
		                 }
					     break;
					case OP_CODE_SEVERIP:
                         if (ParseOptions(op_len,OPTIONS_IP,&(pRxdnet->dhcpframe.options[i]),DHCPReg.severip.bytes) == FALSE) {
                             return;
		                 } 
					default:
					     break;
				}
			} 
			i+=op_len;                          //跳过内容长度
		}
	}

	switch (DHCPReg.state) {
        case DHCP_INIT:
             DHCP_Pack(OP_DHCPDISCOVER);        // 封装发送广播一个DHCPDISCOVER(DHCP发现)包,目的端口填67,        
			 DHCPReg.state = DHCP_SELECT;       //进入SELECT状态
		     break;
        case DHCP_SELECT:  
		     if (pack_type == OP_DHCPOFFER) {   // 收集来自DHCP服务器的DHCPOFFER,客户一般是对第一个到达的数据做出响应,
			     DebugMsg(61);
		         DHCP_Pack(OP_DHCPREQUEST);     // 为此客户给服务器发一个DHCPREQUEST报文,
			     DHCPReg.state = DHCP_REQUEST;  //进入DHCP_REQUEST状态
			 }
		     break;
        case DHCP_REQUEST:
			 if (pack_type == OP_DHCPACK) {     // 如果收到来自DHCP服务器的DHCPACK,客户可以使用得到的IP
			     DebugMsg(62);
			     DHCPReg.state = DHCP_BOUND;    // 进入DHCP_BOUND状态
			     (*DHCPReg.on_bound)();         //调用绑定函数,得到所须要的IP及开启定时器
                 HintMsg(12,NULL);
			 }
		     break;
        case DHCP_BOUND:      // 内部租用定时器开始计时,等待续租时间到50%,或87%时间到,或100%时间到
		     break;
        case DHCP_RENEW:      // 在50%与87%续租状态,如果收到来自DHCP服务器的DHCPACK,客户可以继续使用得到的IP
        case DHCP_REBIND:
			 if (pack_type == OP_DHCPACK) {     
			     DebugMsg(67);
			     DHCPReg.state = DHCP_BOUND;    // 重进入DHCP_BOUND状态
			     (*DHCPReg.on_bound)();         //调用绑定函数,得到所须要的IP及开启定时器
			 } else if (pack_type == OP_DHCPNACK) {    
			     DebugMsg(68);
			     (*DHCPReg.on_release)();       // 如果收到DHCPNACK,服务器不同意,客户立即进入DHCP_INIT初始状态
			 }
			                                    // 都不响应,继续定时,状态不变,判断是否到达100%
		     break;
	}
}


/*
*****************************************************************************************************
*FUNC:  DHCP租用定时器计时判断
*NOTE: 
*****************************************************************************************************
*/
#define REBIND_NUM   3 //发重绑定次数
unsigned char xdata RebindNum=REBIND_NUM;
void DHCPTimer(void)
{
   
    if ((bBound == FALSE) || (DHCPReg.state == DHCP_INIT) || (DHCPMode == FALSE)) {   //初始时没计时 
        return;
	}

	if (DHCPReg.state == DHCP_REBIND) {       //连续  REBIND_NUM 次没ACK 重新申请
	    if (RebindNum > 0) {
            RebindNum--; 
	    } else {
	        HintMsg(13,NULL);
            (*DHCPReg.on_release)();         //释放该IP信息 
			return;
		}
	} else {
        RebindNum = REBIND_NUM;
	}


    if (DHCPReg.timer100.dwords > 0) {
        DHCPReg.timer100.dwords--;
	}
    if (DHCPReg.timer50.dwords > 0) {
        DHCPReg.timer50.dwords--;
	}
    if (DHCPReg.timer87.dwords > 0) {
        DHCPReg.timer87.dwords--;
	}

	if (DHCPReg.timer100.dwords > 0) {
        if ((DHCPReg.timer50.dwords == 0) 
		    && (DHCPReg.state != DHCP_RENEW) 
			&& (DHCPReg.state != DHCP_REBIND)){             //50%续租时间到达
		    DebugMsg(63);
			EA = 0;
	        DHCPReg.transactionid = initial_sequence_nr;    //我的交互ID 
	        initial_sequence_nr += 64000L;
	        EA = 1;
			DHCP_Pack(OP_DHCPREQUEST);   //发送DHCPREQUEST,此时该包报文中包含了一个客户正在使用的IP,
			DHCPReg.state = DHCP_RENEW;  //后进入 DHCP_RENEW 状态;
		}

		if (DHCPReg.timer87.dwords == 0) { //如果续租一直没响应87%时间到
		    DebugMsg(66);
			EA = 0;
	        DHCPReg.transactionid = initial_sequence_nr;   //我的交互ID 
	        initial_sequence_nr += 64000L;
	        EA = 1;
            DHCPReg.state = DHCP_REBIND;                   //切换到重新绑定状态
			DHCP_Pack(OP_DHCPREQUEST);                     //发包:向服务器广播DHCPREQUEST报文
		}
	} else {
	    DebugMsg(69);
        (*DHCPReg.on_release)();                           //释放该IP信息   
	}
}


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -