📄 dhcp.c
字号:
case REBINDING:
if (dhcpStatus.minEvent) //only run if min has changed
{
sendDHCPREQUEST();
dhcpStatus.minEvent=0;
}
if (readUDP(68,&dhcpBuffer)) //check for new data on port 68
{
if ( msg_data == DHCPACK && checkXID())
{
/*start using ip address assigned by dhcpserver*/
ID.IP0=TOINT(dhcpBuffer.data[DHCP_FIELD_YIADDR],dhcpBuffer.data[DHCP_FIELD_YIADDR+1]);
ID.IP1=TOINT(dhcpBuffer.data[DHCP_FIELD_YIADDR+2],dhcpBuffer.data[DHCP_FIELD_YIADDR+3]);
/*write leased ip address to EEPROM */
EEputInt(DHCP_EEADDRESS,ID.IP0);
EEputInt(DHCP_EEADDRESS+2,ID.IP1);
/* read server identifier option */
dhcpStatus.sId0 = TOINT(pdata[2],pdata[3]);
dhcpStatus.sId1 = TOINT(pdata[4],pdata[5]);
dhcpMAC(dhcpStatus.sId0,dhcpStatus.sId1); //dhcpserver (ip,mac) is stored permanently in ARP-table
calcT1();
dhcpStatus.min=0;
dhcpState=BOUND;
}
else if (msg_data == DHCPNAK && checkXID())
{
dhcpState=INIT;
break;
}
}
if (dhcpStatus.min>=dhcpStatus.nextEvent) //leasetime expired, go to state INIT
{
dhcpStatus.min=0;
dhcpState=INIT;
}
break;
case BOUND:
if (dhcpStatus.min>=dhcpStatus.nextEvent) //T1 has occured, enter state RENEWING
{
dhcpStatus.nextEvent=(unsigned int) dhcpStatus.nextEvent*DHCP_T2;
dhcpStatus.min=0;
dhcpState=RENEWING;
}
break;
}
}
}
/*called on every timer0 interrupt*/
void checkDHCP(void)
{
dhcpStatus.cnt++;
/*if arpWait is set, retransmition of dhcprequest id required*/
if (dhcpStatus.arpWait)
{
dhcpStatus.arpWait=0;
sendDHCPREQUEST();
}
if (dhcpStatus.cnt>DHCP_MINUTE) //when one minute is reached, increment min and set minEvent
{
dhcpStatus.cnt=0;
dhcpStatus.min++;
dhcpStatus.minEvent=1;
}
}
/* Waits for timout or UDP datagram on port 68, returns 1 if data, 0 if timeout */
unsigned char wait(unsigned char time)
{
if (time>3)
{
time=3;
}
TCCR1B|=(1<<CTC1 | 1<<CS12 | 1<<CS10); //clear counter on compare match, clock divided by 1024
OCR1A=(time*21845)-1; //wait time is a multiple of 21845/(clkfreq/1024) sec
TIFR|=(1<<OCF1A); //output compare flag 1A is cleared by writing a logic one
TCNT1=0; //clear the counter
for (;;)
{
if (readUDP(68,&dhcpBuffer)) //poll UDP buffer, port 68
{
return 1;
}
else if (TIFR&(1<<OCF1A)) //output compare flag 1A is set, timeout
{
return 0;
}
}
}
/*sends a discover message */
void sendDHCPDISCOVER(void)
{
// unsigned char pos=4;
unsigned char *pdata;
/*generate random xid*/
dhcpStatus.XID0=rand();
dhcpStatus.XID1=rand();
dhcpStatus.XID2=rand();
dhcpStatus.XID3=rand();
stdDHCPMessage(); //consturct the std. header fields
pdata = &dhcpBuffer.data[DHCP_FIELD_OPTIONS+4];
*pdata++ = DHCP_OPTION_MSGTYPE;
*pdata++ = 1;
*pdata++ = DHCPDISCOVER;
*pdata++ = DHCP_OPTION_END;
sendUDP(dhcpBuffer.data,DHCP_FIELD_OPTIONS+8,0xffff,0xffff,68,67);
}
/*sends a request message, the message sent is depent upon the current state*/
void sendDHCPREQUEST(void)
{
// unsigned char pos=4; //start writing after "magic cookie"
unsigned char *pdata = &dhcpBuffer.data[DHCP_FIELD_CIADDR];
stdDHCPMessage();
if (dhcpState==RENEWING || dhcpState==REBINDING) //include client-id if state is RENEWING or REBINDING
{
pdata[DHCP_FIELD_CIADDR]=HI(ID.IP0);
pdata[DHCP_FIELD_CIADDR+1]=LO(ID.IP0);
pdata[DHCP_FIELD_CIADDR+2]=HI(ID.IP1);
pdata[DHCP_FIELD_CIADDR+3]=LO(ID.IP1);
}
pdata = &dhcpBuffer.data[DHCP_FIELD_OPTIONS + 4];
/*write options*/
*pdata++ = DHCP_OPTION_MSGTYPE;
*pdata++ = 1;
*pdata++ = DHCPREQUEST;
if (dhcpState!=RENEWING && dhcpState!=REBINDING) //include requested IP in all states except RENEWING and REBINDING
{
*pdata++ = DHCP_OPTION_REQIP;
*pdata++ = 4;
*pdata++ = HI(dhcpStatus.ip0);
*pdata++ = LO(dhcpStatus.ip0);
*pdata++ = HI(dhcpStatus.ip1);
*pdata++ = LO(dhcpStatus.ip1);
}
if (dhcpState==SELECTING) //include server-id if current state is SELECTING
{
*pdata++ = DHCP_OPTION_SERVERID;
*pdata++ = 4;
*pdata++ = HI(dhcpStatus.sId0);
*pdata++ = LO(dhcpStatus.sId0);
*pdata++ = HI(dhcpStatus.sId1);
*pdata++ = LO(dhcpStatus.sId1);
}
*pdata++ = DHCP_OPTION_END;
if (dhcpState==RENEWING) //unicast message if state is renewing
{
if (!sendUDP(dhcpBuffer.data,DHCP_FIELD_OPTIONS + 17,dhcpStatus.sId0,dhcpStatus.sId1,68,67))
{
/*if the mac is not in the ARP table, set arpWait for later retranMaxsmition*/
dhcpStatus.arpWait=1;
}
}
else
{
sendUDP(dhcpBuffer.data,DHCP_FIELD_OPTIONS + 17 ,0xffff,0xffff,68,67);
}
}
/* writes standard values to message buffer */
void stdDHCPMessage(void)
{
unsigned int * piDHCPData=(unsigned int *) dhcpBuffer.data;
unsigned long * plDHCPData=(unsigned long *) dhcpBuffer.data;
piDHCPData[TO_UINT(DHCP_FIELD_OP)] = 0x0101; //bootrequest + 10MB ethernet
piDHCPData[TO_UINT(DHCP_FIELD_HLEN)] = 0x0006; //mac address is 6 bytes + hops
plDHCPData[TO_UINT(DHCP_FIELD_XID)] = (*(unsigned long *)dhcpStatus.XID0);
piDHCPData[TO_UINT(DHCP_FIELD_SECS)]=0;
piDHCPData[TO_UINT(DHCP_FIELD_FLAGS)]=0;
plDHCPData[TO_ULONG(DHCP_FIELD_CIADDR)]=0;
plDHCPData[TO_ULONG(DHCP_FIELD_YIADDR)]=0;
plDHCPData[TO_ULONG(DHCP_FIELD_SIADDR)]=0;
plDHCPData[TO_ULONG(DHCP_FIELD_GIADDR)]=0;
piDHCPData[TO_UINT(DHCP_FIELD_CHADDR)] = TOINT(LO(ID.MAC0),HI(ID.MAC0)); // Swap bytes before storing to buffer
piDHCPData[TO_UINT(DHCP_FIELD_CHADDR+2)] = TOINT(LO(ID.MAC1),HI(ID.MAC1));
piDHCPData[TO_UINT(DHCP_FIELD_CHADDR+4)] = TOINT(LO(ID.MAC2),HI(ID.MAC2));
piDHCPData[TO_UINT(DHCP_FIELD_OPTIONS)] = TOINT(DHCP_MAGIC_COOKIE1,DHCP_MAGIC_COOKIE0); // Unsigned value, ignore compiler warning
piDHCPData[TO_UINT(DHCP_FIELD_OPTIONS+2)] = TOINT(DHCP_MAGIC_COOKIE3,DHCP_MAGIC_COOKIE2);
}
/*searces for an option in the received dhcp message*/
int findOption(unsigned char opt)
{
unsigned char currentOpt=0;
int pos=4;
currentOpt=dhcpBuffer.data[DHCP_FIELD_OPTIONS+pos];
while (currentOpt!=opt)
{
if (currentOpt==DHCP_OPTION_END) //if end of options, return not found (-1)
{
return -1;
}
pos+=dhcpBuffer.data[DHCP_FIELD_OPTIONS+pos+1]+2;
currentOpt=dhcpBuffer.data[DHCP_FIELD_OPTIONS+pos];
}
return pos;
}
/* Returns 1 if replied XID equals requested XID, 0 otherwise */
unsigned char checkXID(void)
{
unsigned long data = (*(unsigned long *)dhcpBuffer.data[DHCP_FIELD_XID]);
unsigned long xid = (*(unsigned long *)dhcpStatus.XID0);
return (data == xid);
}
/*calculate when state RENEWING should be entered*/
void calcT1(void)
{
unsigned int pos=findOption(DHCP_OPTION_LEASETIME);
unsigned long temp = SwapEndian(*(unsigned long *)dhcpBuffer.data[DHCP_FIELD_OPTIONS+pos+2]);
temp=(temp*DHCP_T1)/60;
if (temp>0xffff)
{
dhcpStatus.nextEvent=0xffff;
}
else
{
dhcpStatus.nextEvent=(unsigned int) temp; //next event, state transmition from BOUND to RENEWING, in minutes
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -