📄 dhcp.c
字号:
*/
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 + -