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         #ifdef DHCP_DEBUG
00111         rprintf("DHCP: Got request ACK, bind complete\r\n");
00112         //debugPrintHexTable(len-DHCP_HEADER_LEN, (packet->options));
00113         // print info
00114         rprintfProgStrM("Ip Addr: ");   netPrintIPAddr(htonl(packet->bootp.yiaddr));rprintfCRLF();
00115         rprintfProgStrM("Netmask: ");   netPrintIPAddr(netmask);                    rprintfCRLF();
00116         rprintfProgStrM("Gateway: ");   netPrintIPAddr(gateway);                    rprintfCRLF();
00117         rprintfProgStrM("LeaseTm: ");   rprintfNum(10,8,FALSE,' ',DhcpLeaseTime);   rprintfCRLF();
00118         #endif
00119 
00120         // assign new network info
00121         ipSetAddress(htonl(packet->bootp.yiaddr), netmask, gateway);
00122     }
00123 }
00124 
00125 void dhcpRequest(void)
00126 {
00127     struct netDhcpHeader* packet;
00128     uint32_t val;
00129     
00130     packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN];
00131 
00132     // build BOOTP/DHCP header
00133     packet->bootp.op = BOOTP_OP_BOOTREQUEST;        // request type
00134     packet->bootp.htype = BOOTP_HTYPE_ETHERNET;
00135     packet->bootp.hlen = BOOTP_HLEN_ETHERNET;
00136     packet->bootp.ciaddr = HTONL(0l);
00137     packet->bootp.yiaddr = HTONL(0l);
00138     packet->bootp.siaddr = HTONL(0l);
00139     packet->bootp.giaddr = HTONL(0l);
00140     nicGetMacAddress(&packet->bootp.chaddr[0]); // fill client hardware address
00141     packet->bootp.xid = DhcpTransactID;
00142     packet->bootp.flags = HTONS(1);
00143     
00144     // build DHCP request
00145     // begin with magic cookie
00146     packet->cookie = 0x63538263;
00147     // set operation
00148     val = DHCP_MSG_DHCPDISCOVER;
00149     dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
00150 
00151     #ifdef DHCP_DEBUG
00152     rprintfProgStrM("DHCP: Sending Query\r\n");
00153     //dhcpPrintHeader(packet);
00154     #endif
00155 
00156     // send request
00157     udpSend(0xFFFFFFFF, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+1, (uint8_t*)packet);
00158 }
00159 
00160 void dhcpRelease(void)
00161 {
00162     struct netDhcpHeader* packet;
00163     uint32_t val;
00164     uint8_t* optptr;
00165     
00166     packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN];
00167 
00168     // build BOOTP/DHCP header
00169     packet->bootp.op = BOOTP_OP_BOOTREQUEST;        // request type
00170     packet->bootp.htype = BOOTP_HTYPE_ETHERNET;
00171     packet->bootp.hlen = BOOTP_HLEN_ETHERNET;
00172     packet->bootp.ciaddr = htonl(ipGetMyAddress());
00173     packet->bootp.yiaddr = HTONL(0l);
00174     packet->bootp.siaddr = HTONL(0l);
00175     packet->bootp.giaddr = HTONL(0l);
00176     nicGetMacAddress(&packet->bootp.chaddr[0]); // fill client hardware address
00177     packet->bootp.xid = DhcpTransactID;         // set trans ID (use part of MAC address)
00178     packet->bootp.flags = HTONS(1);
00179     
00180     // build DHCP request
00181     // begin with magic cookie
00182     packet->cookie = 0x63538263;
00183     // set operation
00184     val = DHCP_MSG_DHCPRELEASE;
00185     optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
00186     // set the server ID
00187     val = htonl(DhcpServerIP);
00188     optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &val);
00189     // request the IP previously offered
00190     optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.ciaddr);
00191 
00192     #ifdef DHCP_DEBUG
00193     rprintfProgStrM("DHCP: Sending Release to "); netPrintIPAddr(DhcpServerIP); rprintfCRLF();
00194     //dhcpPrintHeader(packet);
00195     #endif
00196 
00197     // send release
00198     udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+6+6+1, (uint8_t*)packet);
00199     
00200     // deconfigure ip addressing
00201     ipSetAddress(0,0,0);
00202     DhcpLeaseTime = 0;
00203 }
00204 
00205 void dhcpTimer(void)
00206 {
00207     // this function to be called once per second
00208 
00209     // decrement lease time
00210     if(DhcpLeaseTime)
00211         DhcpLeaseTime--;
00212 }
00213 
00214 uint8_t dhcpGetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr)
00215 {
00216     uint8_t i;
00217 
00218     // parse for desired option
00219     for (;;)
00220     {
00221         // skip pad characters
00222         if(*options == DHCP_OPT_PAD)
00223             options++;
00224         // break if end reached
00225         else if(*options == DHCP_OPT_END)
00226             break;
00227         // check for desired option
00228         else if(*options == optcode)
00229         {
00230             // found desired option
00231             // limit size to actual option length
00232             optlen = MIN(optlen, *(options+1));
00233             //if(*(options+1) < optlen)
00234             //  optlen = *(options+1);
00235             
00236             // copy contents of option
00237             for(i=0; i<optlen; i++)
00238                 *(((uint8_t*)optvalptr)+i) = *(options+i+2);
00239             // return length of option
00240             return *(options+1);
00241         }
00242         else
00243         {
00244             // skip to next option
00245             options++;
00246             options+=*options;
00247             options++;
00248         }
00249     }
00250     // failed to find desired option
00251     return 0;
00252 }
00253 
00254 
00255 uint8_t* dhcpSetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr)
00256 {
00257     // use current options address as write point
00258 
00259     // set optcode
00260     *options++ = optcode;
00261     // set optlen
00262     *options++ = optlen;
00263     // copy in argument/data
00264     while(optlen--)
00265         *options++ = *((uint8_t*)optvalptr)++;
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 Tue Sep 20 03:11:43 2005 for Procyon AVRlib by  doxygen 1.4.2