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