Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

dhcp.c

Go to the documentation of this file.
00001 /*! \file dhcp.c \brief DHCP Protocol Library. */
00002 //*****************************************************************************
00003 //
00004 // File Name    : 'dhcp.c'
00005 // Title        : DHCP Protocol Library
00006 // Author       : Pascal Stang
00007 // Created      : 9/17/2005
00008 // Revised      : 9/17/2005
00009 // Version      : 0.1
00010 // Target MCU   : Atmel AVR series
00011 // Editor Tabs  : 4
00012 //
00013 //*****************************************************************************
00014 
00015 #include "global.h"
00016 #include "net.h"
00017 #include "nic.h"
00018 #include "ip.h"
00019 #include "netstack.h"
00020 
00021 #include "dhcp.h"
00022 
00023 #include "rprintf.h"
00024 
00025 // global variables
00026 uint32_t DhcpServerIP;      ///< IP address of the DHCP server that offered lease
00027 uint32_t DhcpTransactID;    ///< Unique transaction ID that identifies DHCP request/replies
00028 uint32_t DhcpLeaseTime;     ///< Number of seconds left in DHCP lease
00029 
00030 void dhcpInit(void)
00031 {
00032     uint8_t macaddr[6];
00033     
00034     // get interface mac address
00035     nicGetMacAddress(macaddr);
00036     // set transaction ID based on mac address
00037     DhcpTransactID = *((uint32_t*)&macaddr);
00038     // reset lease time
00039     DhcpLeaseTime = 0;
00040 }
00041 
00042 void dhcpIn(unsigned int len, struct netDhcpHeader* packet)
00043 {
00044     uint8_t msgtype;
00045     uint32_t sid;
00046     uint8_t* optptr;
00047     uint32_t val;
00048     uint32_t netmask;
00049     uint32_t gateway;
00050 
00051     #if NET_DEBUG >= 3
00052     dhcpPrintHeader(packet);
00053     #endif
00054 
00055     // check that this is a reply, and for me
00056     if((packet->bootp.op != BOOTP_OP_BOOTREPLY) || (packet->bootp.xid != DhcpTransactID))
00057         return;
00058 
00059     // process incoming packet
00060     // check reply type
00061     dhcpGetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &msgtype);
00062     #if NET_DEBUG >= 2
00063     rprintf("DHCP: Received msgtype = %d\r\n", msgtype);
00064     #endif
00065     
00066     if(msgtype == DHCP_MSG_DHCPOFFER)
00067     {
00068         // get DHCP server ID
00069         dhcpGetOption(packet->options, DHCP_OPT_SERVERID, 4, &sid);
00070         #ifdef DHCP_DEBUG
00071         rprintfProgStrM("DHCP: Got offer from server "); netPrintIPAddr(htonl(sid)); rprintfCRLF();
00072         #endif
00073 
00074         // build DHCP request (on top of this reply)
00075         packet->bootp.op = BOOTP_OP_BOOTREQUEST;        // request type
00076         // set operation
00077         val = DHCP_MSG_DHCPREQUEST;
00078         optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
00079         // set the server ID
00080         optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &sid);
00081         // request the IP previously offered
00082         optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.yiaddr);
00083         // request additional information
00084         ((uint8_t*)&val)[0] = DHCP_OPT_NETMASK;
00085         ((uint8_t*)&val)[1] = DHCP_OPT_ROUTERS;
00086         ((uint8_t*)&val)[2] = DHCP_OPT_DNSSERVERS;
00087         ((uint8_t*)&val)[3] = DHCP_OPT_DOMAINNAME;
00088         optptr = dhcpSetOption(optptr, DHCP_OPT_PARAMREQLIST, 4, &val);
00089 
00090         #ifdef DHCP_DEBUG
00091         rprintfProgStrM("DHCP: Sending request in response to offer\r\n");
00092         #endif
00093         // send DHCP request
00094         DhcpServerIP = htonl(sid);
00095         udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+6+6+6+1, (uint8_t*)packet);
00096 
00097     }
00098     else if(msgtype == DHCP_MSG_DHCPACK)
00099     {
00100         // get netmask
00101         dhcpGetOption(packet->options, DHCP_OPT_NETMASK, 4, &val);
00102         netmask = htonl(val);
00103         // get gateway
00104         dhcpGetOption(packet->options, DHCP_OPT_ROUTERS, 4, &val);
00105         gateway = htonl(val);
00106         // get gateway
00107         dhcpGetOption(packet->options, DHCP_OPT_LEASETIME, 4, &val);
00108         DhcpLeaseTime = htonl(val);
00109 
00110         // assign new network info
00111         ipSetConfig(htonl(packet->bootp.yiaddr), netmask, gateway);
00112 
00113         #ifdef DHCP_DEBUG
00114         rprintf("DHCP: Got request ACK, bind complete\r\n");
00115         //debugPrintHexTable(len-DHCP_HEADER_LEN, (packet->options));
00116         // print info
00117         ipPrintConfig(ipGetConfig());
00118         rprintfProgStrM("LeaseTm : ");  rprintfNum(10,8,FALSE,' ',DhcpLeaseTime);   rprintfCRLF();
00119         #endif
00120     }
00121 }
00122 
00123 void dhcpRequest(void)
00124 {
00125     struct netDhcpHeader* packet;
00126     uint32_t val;
00127     
00128     packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN];
00129 
00130     // build BOOTP/DHCP header
00131     packet->bootp.op = BOOTP_OP_BOOTREQUEST;        // request type
00132     packet->bootp.htype = BOOTP_HTYPE_ETHERNET;
00133     packet->bootp.hlen = BOOTP_HLEN_ETHERNET;
00134     packet->bootp.ciaddr = htonl(ipGetConfig()->ip);
00135     packet->bootp.yiaddr = HTONL(0l);
00136     packet->bootp.siaddr = HTONL(0l);
00137     packet->bootp.giaddr = HTONL(0l);
00138     nicGetMacAddress(&packet->bootp.chaddr[0]); // fill client hardware address
00139     packet->bootp.xid = DhcpTransactID;
00140     packet->bootp.flags = HTONS(1);
00141     
00142     // build DHCP request
00143     // begin with magic cookie
00144     packet->cookie = 0x63538263;
00145     // set operation
00146     val = DHCP_MSG_DHCPDISCOVER;
00147     dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
00148 
00149     #ifdef DHCP_DEBUG
00150     rprintfProgStrM("DHCP: Sending Query\r\n");
00151     //dhcpPrintHeader(packet);
00152     #endif
00153 
00154     // send request
00155     udpSend(0xFFFFFFFF, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+1, (uint8_t*)packet);
00156 }
00157 
00158 void dhcpRelease(void)
00159 {
00160     struct netDhcpHeader* packet;
00161     uint32_t val;
00162     uint8_t* optptr;
00163     
00164     packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN];
00165 
00166     // build BOOTP/DHCP header
00167     packet->bootp.op = BOOTP_OP_BOOTREQUEST;        // request type
00168     packet->bootp.htype = BOOTP_HTYPE_ETHERNET;
00169     packet->bootp.hlen = BOOTP_HLEN_ETHERNET;
00170     packet->bootp.ciaddr = htonl(ipGetConfig()->ip);
00171     packet->bootp.yiaddr = HTONL(0l);
00172     packet->bootp.siaddr = HTONL(0l);
00173     packet->bootp.giaddr = HTONL(0l);
00174     nicGetMacAddress(&packet->bootp.chaddr[0]); // fill client hardware address
00175     packet->bootp.xid = DhcpTransactID;         // set trans ID (use part of MAC address)
00176     packet->bootp.flags = HTONS(1);
00177     
00178     // build DHCP request
00179     // begin with magic cookie
00180     packet->cookie = 0x63538263;
00181     // set operation
00182     val = DHCP_MSG_DHCPRELEASE;
00183     optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
00184     // set the server ID
00185     val = htonl(DhcpServerIP);
00186     optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &val);
00187     // request the IP previously offered
00188     optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.ciaddr);
00189 
00190     #ifdef DHCP_DEBUG
00191     rprintfProgStrM("DHCP: Sending Release to "); netPrintIPAddr(DhcpServerIP); rprintfCRLF();
00192     //dhcpPrintHeader(packet);
00193     #endif
00194 
00195     // send release
00196     udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+6+6+1, (uint8_t*)packet);
00197     
00198     // deconfigure ip addressing
00199     ipSetConfig(0,0,0);
00200     DhcpLeaseTime = 0;
00201 }
00202 
00203 void dhcpTimer(void)
00204 {
00205     // this function to be called once per second
00206 
00207     // decrement lease time
00208     if(DhcpLeaseTime)
00209         DhcpLeaseTime--;
00210 }
00211 
00212 uint8_t dhcpGetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr)
00213 {
00214     uint8_t i;
00215 
00216     // parse for desired option
00217     for (;;)
00218     {
00219         // skip pad characters
00220         if(*options == DHCP_OPT_PAD)
00221             options++;
00222         // break if end reached
00223         else if(*options == DHCP_OPT_END)
00224             break;
00225         // check for desired option
00226         else if(*options == optcode)
00227         {
00228             // found desired option
00229             // limit size to actual option length
00230             optlen = MIN(optlen, *(options+1));
00231             //if(*(options+1) < optlen)
00232             //  optlen = *(options+1);
00233             
00234             // copy contents of option
00235             for(i=0; i<optlen; i++)
00236                 *(((uint8_t*)optvalptr)+i) = *(options+i+2);
00237             // return length of option
00238             return *(options+1);
00239         }
00240         else
00241         {
00242             // skip to next option
00243             options++;
00244             options+=*options;
00245             options++;
00246         }
00247     }
00248     // failed to find desired option
00249     return 0;
00250 }
00251 
00252 
00253 uint8_t* dhcpSetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr)
00254 {
00255     // use current options address as write point
00256 
00257     // set optcode
00258     *options++ = optcode;
00259     // set optlen
00260     *options++ = optlen;
00261     // copy in argument/data
00262     while(optlen--)
00263     {
00264         *options++ = *(uint8_t*)optvalptr++;
00265     }
00266     // write end marker
00267     *options = DHCP_OPT_END;
00268 
00269     // return address of end marker, to be used as a future write point
00270     return options;
00271 }
00272 
00273 
00274 #ifdef DHCP_DEBUG_PRINT
00275 void dhcpPrintHeader(struct netDhcpHeader* packet)
00276 {
00277     rprintfProgStrM("DHCP Packet:\r\n");
00278     // print op
00279     rprintfProgStrM("Op      : ");
00280     switch(packet->bootp.op)
00281     {
00282     case BOOTP_OP_BOOTREQUEST:  rprintfProgStrM("BOOTREQUEST"); break;
00283     case BOOTP_OP_BOOTREPLY:    rprintfProgStrM("BOOTREPLY"); break;
00284     default:                    rprintfProgStrM("UNKNOWN"); break;
00285     }
00286     rprintfCRLF();
00287     // print transaction ID
00288     rprintfProgStrM("XID     : 0x");    rprintfu32(packet->bootp.xid);              rprintfCRLF();
00289     // print client IP address
00290     rprintfProgStrM("ClIpAddr: ");  netPrintIPAddr(htonl(packet->bootp.ciaddr));    rprintfCRLF();
00291     // print 'your' IP address
00292     rprintfProgStrM("YrIpAddr: ");  netPrintIPAddr(htonl(packet->bootp.yiaddr));    rprintfCRLF();
00293     // print server IP address
00294     rprintfProgStrM("SvIpAddr: ");  netPrintIPAddr(htonl(packet->bootp.siaddr));    rprintfCRLF();
00295     // print gateway IP address
00296     rprintfProgStrM("GwIpAddr: ");  netPrintIPAddr(htonl(packet->bootp.giaddr));    rprintfCRLF();
00297     // print client hardware address
00298     rprintfProgStrM("ClHwAddr: ");  netPrintEthAddr((struct netEthAddr*)packet->bootp.chaddr);  rprintfCRLF();
00299 }
00300 #endif

Generated on Sun Oct 29 03:41:07 2006 for Procyon AVRlib by  doxygen 1.4.2