?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 6

?prevdifflink? - Blame - ?getfile?

/*! \file dhcp.c \brief DHCP Protocol Library. */
//*****************************************************************************
//
// File Name    : 'dhcp.c'
// Title                : DHCP Protocol Library
// Author               : Pascal Stang
// Created              : 9/17/2005
// Revised              : 9/17/2005
// Version              : 0.1
// Target MCU   : Atmel AVR series
// Editor Tabs  : 4
//
//*****************************************************************************

#include "global.h"
#include "net.h"
#include "nic.h"
#include "ip.h"
#include "netstack.h"

#include "dhcp.h"

#include "rprintf.h"

// global variables
uint32_t DhcpServerIP;          ///< IP address of the DHCP server that offered lease
uint32_t DhcpTransactID;        ///< Unique transaction ID that identifies DHCP request/replies
uint32_t DhcpLeaseTime;         ///< Number of seconds left in DHCP lease

void dhcpInit(void)
{
        uint8_t macaddr[6];
        
        // get interface mac address
        nicGetMacAddress(macaddr);
        // set transaction ID based on mac address
        DhcpTransactID = *((uint32_t*)&macaddr);
        // reset lease time
        DhcpLeaseTime = 0;
}

void dhcpIn(unsigned int len, struct netDhcpHeader* packet)
{
        uint8_t msgtype;
        uint32_t sid;
        uint8_t* optptr;
        uint32_t val;
        uint32_t netmask;
        uint32_t gateway;

        #if NET_DEBUG >= 3
        dhcpPrintHeader(packet);
        #endif

        // check that this is a reply, and for me
        if((packet->bootp.op != BOOTP_OP_BOOTREPLY) || (packet->bootp.xid != DhcpTransactID))
                return;

        // process incoming packet
        // check reply type
        dhcpGetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &msgtype);
        #if NET_DEBUG >= 2
        rprintf("DHCP: Received msgtype = %d\r\n", msgtype);
        #endif
        
        if(msgtype == DHCP_MSG_DHCPOFFER)
        {
                // get DHCP server ID
                dhcpGetOption(packet->options, DHCP_OPT_SERVERID, 4, &sid);
                #ifdef DHCP_DEBUG
                rprintfProgStrM("DHCP: Got offer from server "); netPrintIPAddr(htonl(sid)); rprintfCRLF();
                #endif

                // build DHCP request (on top of this reply)
                packet->bootp.op = BOOTP_OP_BOOTREQUEST;                // request type
                // set operation
                val = DHCP_MSG_DHCPREQUEST;
                optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
                // set the server ID
                optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &sid);
                // request the IP previously offered
                optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.yiaddr);
                // request additional information
                ((uint8_t*)&val)[0] = DHCP_OPT_NETMASK;
                ((uint8_t*)&val)[1] = DHCP_OPT_ROUTERS;
                ((uint8_t*)&val)[2] = DHCP_OPT_DNSSERVERS;
                ((uint8_t*)&val)[3] = DHCP_OPT_DOMAINNAME;
                optptr = dhcpSetOption(optptr, DHCP_OPT_PARAMREQLIST, 4, &val);

                #ifdef DHCP_DEBUG
                rprintfProgStrM("DHCP: Sending request in response to offer\r\n");
                #endif
                // send DHCP request
                DhcpServerIP = htonl(sid);
                udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+6+6+6+1, (uint8_t*)packet);

        }
        else if(msgtype == DHCP_MSG_DHCPACK)
        {
                // get netmask
                dhcpGetOption(packet->options, DHCP_OPT_NETMASK, 4, &val);
                netmask = htonl(val);
                // get gateway
                dhcpGetOption(packet->options, DHCP_OPT_ROUTERS, 4, &val);
                gateway = htonl(val);
                // get gateway
                dhcpGetOption(packet->options, DHCP_OPT_LEASETIME, 4, &val);
                DhcpLeaseTime = htonl(val);

                // assign new network info
                ipSetConfig(htonl(packet->bootp.yiaddr), netmask, gateway);

                #ifdef DHCP_DEBUG
                rprintf("DHCP: Got request ACK, bind complete\r\n");
                //debugPrintHexTable(len-DHCP_HEADER_LEN, (packet->options));
                // print info
                ipPrintConfig(ipGetConfig());
                rprintfProgStrM("LeaseTm : ");  rprintfNum(10,8,FALSE,' ',DhcpLeaseTime);       rprintfCRLF();
                #endif
        }
}

void dhcpRequest(void)
{
        struct netDhcpHeader* packet;
        uint32_t val;
        
        packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN];

        // build BOOTP/DHCP header
        packet->bootp.op = BOOTP_OP_BOOTREQUEST;                // request type
        packet->bootp.htype = BOOTP_HTYPE_ETHERNET;
        packet->bootp.hlen = BOOTP_HLEN_ETHERNET;
        packet->bootp.ciaddr = htonl(ipGetConfig()->ip);
        packet->bootp.yiaddr = HTONL(0l);
        packet->bootp.siaddr = HTONL(0l);
        packet->bootp.giaddr = HTONL(0l);
        nicGetMacAddress(&packet->bootp.chaddr[0]);     // fill client hardware address
        packet->bootp.xid = DhcpTransactID;
        packet->bootp.flags = HTONS(1);
        
        // build DHCP request
        // begin with magic cookie
        packet->cookie = 0x63538263;
        // set operation
        val = DHCP_MSG_DHCPDISCOVER;
        dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);

        #ifdef DHCP_DEBUG
        rprintfProgStrM("DHCP: Sending Query\r\n");
        //dhcpPrintHeader(packet);
        #endif

        // send request
        udpSend(0xFFFFFFFF, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+1, (uint8_t*)packet);
}

void dhcpRelease(void)
{
        struct netDhcpHeader* packet;
        uint32_t val;
        uint8_t* optptr;
        
        packet = (struct netDhcpHeader*)&netstackGetBuffer()[ETH_HEADER_LEN+IP_HEADER_LEN+UDP_HEADER_LEN];

        // build BOOTP/DHCP header
        packet->bootp.op = BOOTP_OP_BOOTREQUEST;                // request type
        packet->bootp.htype = BOOTP_HTYPE_ETHERNET;
        packet->bootp.hlen = BOOTP_HLEN_ETHERNET;
        packet->bootp.ciaddr = htonl(ipGetConfig()->ip);
        packet->bootp.yiaddr = HTONL(0l);
        packet->bootp.siaddr = HTONL(0l);
        packet->bootp.giaddr = HTONL(0l);
        nicGetMacAddress(&packet->bootp.chaddr[0]);     // fill client hardware address
        packet->bootp.xid = DhcpTransactID;                     // set trans ID (use part of MAC address)
        packet->bootp.flags = HTONS(1);
        
        // build DHCP request
        // begin with magic cookie
        packet->cookie = 0x63538263;
        // set operation
        val = DHCP_MSG_DHCPRELEASE;
        optptr = dhcpSetOption(packet->options, DHCP_OPT_DHCPMSGTYPE, 1, &val);
        // set the server ID
        val = htonl(DhcpServerIP);
        optptr = dhcpSetOption(optptr, DHCP_OPT_SERVERID, 4, &val);
        // request the IP previously offered
        optptr = dhcpSetOption(optptr, DHCP_OPT_REQUESTEDIP, 4, &packet->bootp.ciaddr);

        #ifdef DHCP_DEBUG
        rprintfProgStrM("DHCP: Sending Release to "); netPrintIPAddr(DhcpServerIP); rprintfCRLF();
        //dhcpPrintHeader(packet);
        #endif

        // send release
        udpSend(DhcpServerIP, DHCP_UDP_SERVER_PORT, DHCP_HEADER_LEN+3+6+6+1, (uint8_t*)packet);
        
        // deconfigure ip addressing
        ipSetConfig(0,0,0);
        DhcpLeaseTime = 0;
}

void dhcpTimer(void)
{
        // this function to be called once per second

        // decrement lease time
        if(DhcpLeaseTime)
                DhcpLeaseTime--;
}

uint8_t dhcpGetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr)
{
        uint8_t i;

        // parse for desired option
        for (;;)
        {
                // skip pad characters
                if(*options == DHCP_OPT_PAD)
                        options++;
                // break if end reached
                else if(*options == DHCP_OPT_END)
                        break;
                // check for desired option
                else if(*options == optcode)
                {
                        // found desired option
                        // limit size to actual option length
                        optlen = MIN(optlen, *(options+1));
                        //if(*(options+1) < optlen)
                        //      optlen = *(options+1);
                        
                        // copy contents of option
                        for(i=0; i<optlen; i++)
                                *(((uint8_t*)optvalptr)+i) = *(options+i+2);
                        // return length of option
                        return *(options+1);
                }
                else
                {
                        // skip to next option
                        options++;
                        options+=*options;
                        options++;
                }
        }
        // failed to find desired option
        return 0;
}


uint8_t* dhcpSetOption(uint8_t* options, uint8_t optcode, uint8_t optlen, void* optvalptr)
{
        // use current options address as write point

        // set optcode
        *options++ = optcode;
        // set optlen
        *options++ = optlen;
        // copy in argument/data
        while(optlen--)
        {
                *options++ = *(uint8_t*)optvalptr++;
        }
        // write end marker
        *options = DHCP_OPT_END;

        // return address of end marker, to be used as a future write point
        return options;
}


#ifdef DHCP_DEBUG_PRINT
void dhcpPrintHeader(struct netDhcpHeader* packet)
{
        rprintfProgStrM("DHCP Packet:\r\n");
        // print op
        rprintfProgStrM("Op      : ");
        switch(packet->bootp.op)
        {
        case BOOTP_OP_BOOTREQUEST:      rprintfProgStrM("BOOTREQUEST"); break;
        case BOOTP_OP_BOOTREPLY:        rprintfProgStrM("BOOTREPLY"); break;
        default:                                        rprintfProgStrM("UNKNOWN"); break;
        }
        rprintfCRLF();
        // print transaction ID
        rprintfProgStrM("XID     : 0x");        rprintfu32(packet->bootp.xid);                          rprintfCRLF();
        // print client IP address
        rprintfProgStrM("ClIpAddr: ");  netPrintIPAddr(htonl(packet->bootp.ciaddr));    rprintfCRLF();
        // print 'your' IP address
        rprintfProgStrM("YrIpAddr: ");  netPrintIPAddr(htonl(packet->bootp.yiaddr));    rprintfCRLF();
        // print server IP address
        rprintfProgStrM("SvIpAddr: ");  netPrintIPAddr(htonl(packet->bootp.siaddr));    rprintfCRLF();
        // print gateway IP address
        rprintfProgStrM("GwIpAddr: ");  netPrintIPAddr(htonl(packet->bootp.giaddr));    rprintfCRLF();
        // print client hardware address
        rprintfProgStrM("ClHwAddr: ");  netPrintEthAddr((struct netEthAddr*)packet->bootp.chaddr);      rprintfCRLF();
}
#endif
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3