?? 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 + -