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

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

/*********************************************************************
 *
 *  Dynamic Host Configuration Protocol (DHCP) Server
 *  Module for Microchip TCP/IP Stack
 *       -Provides automatic IP address, subnet mask, gateway address, 
 *        DNS server address, and other configuration parameters on DHCP 
 *        enabled networks.
 *       -Reference: RFC 2131, 2132
 *
 *********************************************************************
 * FileName:        DHCPs.c
 * Dependencies:    UDP, ARP, Tick
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 *                                      Microchip C30 v3.12 or higher
 *                                      Microchip C18 v3.30 or higher
 *                                      HI-TECH PICC-18 PRO 9.63PL2 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 *              ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 *              used in conjunction with a Microchip ethernet controller for
 *              the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date            Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Howard Schlunder     02/28/07        Original
 ********************************************************************/
#define __DHCPS_C

#include "TCPIPConfig.h"

#if defined(STACK_USE_DHCP_SERVER)

#include "TCPIP Stack/TCPIP.h"

// Duration of our DHCP Lease in seconds.  This is extrememly short so 
// the client won't use our IP for long if we inadvertantly 
// provide a lease on a network that has a more authoratative DHCP server.
#define DHCP_LEASE_DURATION                             60ul
/// Ignore: #define DHCP_MAX_LEASES                                     2               // Not implemented

// DHCP Control Block.  Lease IP address is derived from index into DCB array.
typedef struct
{
        DWORD           LeaseExpires;   // Expiration time for this lease
        MAC_ADDR        ClientMAC;              // Client's MAC address.  Multicase bit is used to determine if a lease is given out or not
        enum 
        {
                LEASE_UNUSED = 0,
                LEASE_REQUESTED,
                LEASE_GRANTED
        } smLease;                                      // Status of this lease
} DHCP_CONTROL_BLOCK;

static UDP_SOCKET                       MySocket;               // Socket used by DHCP Server
static IP_ADDR                          DHCPNextLease;  // IP Address to provide for next lease
/// Ignore: static DHCP_CONTROL_BLOCK   DCB[DHCP_MAX_LEASES];   // Not Implmented
BOOL                                            bDHCPServerEnabled = TRUE;      // Whether or not the DHCP server is enabled

static void DHCPReplyToDiscovery(BOOTP_HEADER *Header);
static void DHCPReplyToRequest(BOOTP_HEADER *Header, BOOL bAccept);


/*****************************************************************************
  Function:
        void DHCPServerTask(void)

  Summary:
        Performs periodic DHCP server tasks.

  Description:
        This function performs any periodic tasks requied by the DHCP server 
        module, such as processing DHCP requests and distributing IP addresses.

  Precondition:
        None

  Parameters:
        None

  Returns:
        None
  ***************************************************************************/
void DHCPServerTask(void)
{
        BYTE                            i;
        BYTE                            Option, Len;
        BOOTP_HEADER            BOOTPHeader;
        DWORD                           dw;
        BOOL                            bAccept;
        static enum
        {
                DHCP_OPEN_SOCKET,
                DHCP_LISTEN
        } smDHCPServer = DHCP_OPEN_SOCKET;

#if defined(STACK_USE_ZEROCONF_LINK_LOCAL)
        static BOOL bLeaseAvailable = TRUE;
#endif

#if defined(STACK_USE_DHCP_CLIENT)
        // Make sure we don't clobber anyone else's DHCP server
        if(DHCPIsServerDetected(0))
                return;
#endif

        if(!bDHCPServerEnabled)
                return;

        switch(smDHCPServer)
        {
                case DHCP_OPEN_SOCKET:
                        // Obtain a UDP socket to listen/transmit on
                        MySocket = UDPOpen(DHCP_SERVER_PORT, NULL, DHCP_CLIENT_PORT);
                        if(MySocket == INVALID_UDP_SOCKET)
                                break;


                        // Decide which address to lease out
                        // Note that this needs to be changed if we are to 
                        // support more than one lease
                        DHCPNextLease.Val = (AppConfig.MyIPAddr.Val & AppConfig.MyMask.Val) + 0x02000000;
                        if(DHCPNextLease.v[3] == 255u)
                                DHCPNextLease.v[3] += 0x03;
                        if(DHCPNextLease.v[3] == 0u)
                                DHCPNextLease.v[3] += 0x02;

                        smDHCPServer++;

                case DHCP_LISTEN:
                        // Check to see if a valid DHCP packet has arrived
                        if(UDPIsGetReady(MySocket) < 241u)
                                break;

                        // Retrieve the BOOTP header
                        UDPGetArray((BYTE*)&BOOTPHeader, sizeof(BOOTPHeader));

                        bAccept = (BOOTPHeader.ClientIP.Val == DHCPNextLease.Val) || (BOOTPHeader.ClientIP.Val == 0x00000000u);

                        // Validate first three fields
                        if(BOOTPHeader.MessageType != 1u)
                                break;
                        if(BOOTPHeader.HardwareType != 1u)
                                break;
                        if(BOOTPHeader.HardwareLen != 6u)
                                break;

                        // Throw away 10 unused bytes of hardware address,
                        // server host name, and boot file name -- unsupported/not needed.
                        for(i = 0; i < 64+128+(16-sizeof(MAC_ADDR)); i++)
                                UDPGet(&Option);

                        // Obtain Magic Cookie and verify
                        UDPGetArray((BYTE*)&dw, sizeof(DWORD));
                        if(dw != 0x63538263ul)
                                break;

                        // Obtain options
                        while(1)
                        {
                                // Get option type
                                if(!UDPGet(&Option))
                                        break;
                                if(Option == DHCP_END_OPTION)
                                        break;

                                // Get option length
                                UDPGet(&Len);
        
                                // Process option
                                switch(Option)
                                {
                                        case DHCP_MESSAGE_TYPE:
                                                UDPGet(&i);
                                                switch(i)
                                                {
                                                        case DHCP_DISCOVER_MESSAGE:
                                                                DHCPReplyToDiscovery(&BOOTPHeader);
                                                                break;

                                                        case DHCP_REQUEST_MESSAGE:
                                #if defined(STACK_USE_ZEROCONF_LINK_LOCAL)
                                                                if ( (BOOTPHeader.ClientIP.Val == 0x00000000u) &&
                                                                         (bLeaseAvailable == FALSE) )
                                                                {
                                                                        // Lease available only to the current lease holder
                                                                        break;
                                                                }
                                                                #endif

                                                                DHCPReplyToRequest(&BOOTPHeader, bAccept);

                                #if defined(STACK_USE_ZEROCONF_LINK_LOCAL)
                                                                bLeaseAvailable = FALSE;
                                                                #endif

                                                                break;

                                                        // Need to handle these if supporting more than one DHCP lease
                                                        case DHCP_RELEASE_MESSAGE:
                                                        case DHCP_DECLINE_MESSAGE:
                                                                break;
                                                }
                                                break;

                                        case DHCP_PARAM_REQUEST_IP_ADDRESS:
                                                if(Len == 4u)
                                                {
                                                        // Get the requested IP address and see if it is the one we have on offer.
                                                        UDPGetArray((BYTE*)&dw, 4);
                                                        Len -= 4;
                                                        bAccept = (dw == DHCPNextLease.Val);
                                                }
                                                break;

                                        case DHCP_END_OPTION:
                                                UDPDiscard();
                                                return;
                                }

                                // Remove any unprocessed bytes that we don't care about
                                while(Len--)
                                {
                                        UDPGet(&i);
                                }
                        }                       

                        UDPDiscard();
                        break;
        }
}


/*****************************************************************************
  Function:
        static void DHCPReplyToDiscovery(BOOTP_HEADER *Header)

  Summary:
        Replies to a DHCP Discover message.

  Description:
        This function replies to a DHCP Discover message by sending out a 
        DHCP Offer message.

  Precondition:
        None

  Parameters:
        Header - the BootP header this is in response to.

  Returns:
        None
  ***************************************************************************/
static void DHCPReplyToDiscovery(BOOTP_HEADER *Header)
{
        BYTE i;

        // Set the correct socket to active and ensure that 
        // enough space is available to generate the DHCP response
        if(UDPIsPutReady(MySocket) < 300u)
                return;

        // Begin putting the BOOTP Header and DHCP options
        UDPPut(BOOT_REPLY);                     // Message Type: 2 (BOOTP Reply)
        // Reply with the same Hardware Type, Hardware Address Length, Hops, and Transaction ID fields
        UDPPutArray((BYTE*)&(Header->HardwareType), 7);
        UDPPut(0x00);                           // Seconds Elapsed: 0 (Not used)
        UDPPut(0x00);                           // Seconds Elapsed: 0 (Not used)
        UDPPutArray((BYTE*)&(Header->BootpFlags), sizeof(Header->BootpFlags));
        UDPPut(0x00);                           // Your (client) IP Address: 0.0.0.0 (none yet assigned)
        UDPPut(0x00);                           // Your (client) IP Address: 0.0.0.0 (none yet assigned)
        UDPPut(0x00);                           // Your (client) IP Address: 0.0.0.0 (none yet assigned)
        UDPPut(0x00);                           // Your (client) IP Address: 0.0.0.0 (none yet assigned)
        UDPPutArray((BYTE*)&DHCPNextLease, sizeof(IP_ADDR));    // Lease IP address to give out
        UDPPut(0x00);                           // Next Server IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Next Server IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Next Server IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Next Server IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Relay Agent IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Relay Agent IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Relay Agent IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Relay Agent IP Address: 0.0.0.0 (not used)
        UDPPutArray((BYTE*)&(Header->ClientMAC), sizeof(MAC_ADDR));     // Client MAC address: Same as given by client
        for(i = 0; i < 64+128+(16-sizeof(MAC_ADDR)); i++)       // Remaining 10 bytes of client hardware address, server host name: Null string (not used)
                UDPPut(0x00);                                                                   // Boot filename: Null string (not used)
        UDPPut(0x63);                           // Magic Cookie: 0x63538263
        UDPPut(0x82);                           // Magic Cookie: 0x63538263
        UDPPut(0x53);                           // Magic Cookie: 0x63538263
        UDPPut(0x63);                           // Magic Cookie: 0x63538263
        
        // Options: DHCP Offer
        UDPPut(DHCP_MESSAGE_TYPE);      
        UDPPut(1);
        UDPPut(DHCP_OFFER_MESSAGE);

        // Option: Subnet Mask
        UDPPut(DHCP_SUBNET_MASK);
        UDPPut(sizeof(IP_ADDR));
        UDPPutArray((BYTE*)&AppConfig.MyMask, sizeof(IP_ADDR));

        // Option: Lease duration
        UDPPut(DHCP_IP_LEASE_TIME);
        UDPPut(4);
        UDPPut((DHCP_LEASE_DURATION>>24) & 0xFF);
        UDPPut((DHCP_LEASE_DURATION>>16) & 0xFF);
        UDPPut((DHCP_LEASE_DURATION>>8) & 0xFF);
        UDPPut((DHCP_LEASE_DURATION) & 0xFF);

        // Option: Server identifier
        UDPPut(DHCP_SERVER_IDENTIFIER); 
        UDPPut(sizeof(IP_ADDR));
        UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR));

        // Option: Router/Gateway address
        UDPPut(DHCP_ROUTER);            
        UDPPut(sizeof(IP_ADDR));
        UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR));

        // Option: DNS server address
        UDPPut(DHCP_DNS);
        UDPPut(sizeof(IP_ADDR));
        UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR));

        // No more options, mark ending
        UDPPut(DHCP_END_OPTION);

        // Add zero padding to ensure compatibility with old BOOTP relays that discard small packets (<300 UDP octets)
        while(UDPTxCount < 300u)
                UDPPut(0); 

        // Force remote destination address to be the broadcast address, regardless 
        // of what the node's source IP address was (to ensure we don't try to 
        // unicast to 0.0.0.0).
        memset((void*)&UDPSocketInfo[MySocket].remoteNode, 0xFF, sizeof(NODE_INFO));

        // Transmit the packet
        UDPFlush();
}


/*****************************************************************************
  Function:
        static void DHCPReplyToRequest(BOOTP_HEADER *Header, BOOL bAccept)

  Summary:
        Replies to a DHCP Request message.

  Description:
        This function replies to a DHCP Request message by sending out a 
        DHCP Acknowledge message.

  Precondition:
        None

  Parameters:
        Header - the BootP header this is in response to.
        bAccept - whether or not we've accepted this request

  Returns:
        None
  
  Internal:
        Needs to support more than one simultaneous lease in the future.
  ***************************************************************************/
static void DHCPReplyToRequest(BOOTP_HEADER *Header, BOOL bAccept)
{
        BYTE i;

        // Set the correct socket to active and ensure that 
        // enough space is available to generate the DHCP response
        if(UDPIsPutReady(MySocket) < 300u)
                return;

        // Search through all remaining options and look for the Requested IP address field
        // Obtain options
        while(UDPIsGetReady(MySocket))
        {
                BYTE Option, Len;
                DWORD dw;

                // Get option type
                if(!UDPGet(&Option))
                        break;
                if(Option == DHCP_END_OPTION)
                        break;

                // Get option length
                UDPGet(&Len);

                // Process option
                if((Option == DHCP_PARAM_REQUEST_IP_ADDRESS) && (Len == 4u))
                {
                        // Get the requested IP address and see if it is the one we have on offer.  If not, we should send back a NAK, but since there could be some other DHCP server offering this address, we'll just silently ignore this request.
                        UDPGetArray((BYTE*)&dw, 4);
                        Len -= 4;
                        if(dw != DHCPNextLease.Val)
                        {
                                bAccept = FALSE;
                        }
                        break;
                }

                // Remove the unprocessed bytes that we don't care about
                while(Len--)
                {
                        UDPGet(&i);
                }
        }                       

        // Begin putting the BOOTP Header and DHCP options
        UDPPut(BOOT_REPLY);                     // Message Type: 2 (BOOTP Reply)
        // Reply with the same Hardware Type, Hardware Address Length, Hops, and Transaction ID fields
        UDPPutArray((BYTE*)&(Header->HardwareType), 7);
        UDPPut(0x00);                           // Seconds Elapsed: 0 (Not used)
        UDPPut(0x00);                           // Seconds Elapsed: 0 (Not used)
        UDPPutArray((BYTE*)&(Header->BootpFlags), sizeof(Header->BootpFlags));
        UDPPutArray((BYTE*)&(Header->ClientIP), sizeof(IP_ADDR));// Your (client) IP Address:
        UDPPutArray((BYTE*)&DHCPNextLease, sizeof(IP_ADDR));    // Lease IP address to give out
        UDPPut(0x00);                           // Next Server IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Next Server IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Next Server IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Next Server IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Relay Agent IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Relay Agent IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Relay Agent IP Address: 0.0.0.0 (not used)
        UDPPut(0x00);                           // Relay Agent IP Address: 0.0.0.0 (not used)
        UDPPutArray((BYTE*)&(Header->ClientMAC), sizeof(MAC_ADDR));     // Client MAC address: Same as given by client
        for(i = 0; i < 64+128+(16-sizeof(MAC_ADDR)); i++)       // Remaining 10 bytes of client hardware address, server host name: Null string (not used)
                UDPPut(0x00);                                                                   // Boot filename: Null string (not used)
        UDPPut(0x63);                           // Magic Cookie: 0x63538263
        UDPPut(0x82);                           // Magic Cookie: 0x63538263
        UDPPut(0x53);                           // Magic Cookie: 0x63538263
        UDPPut(0x63);                           // Magic Cookie: 0x63538263
        
        // Options: DHCP lease ACKnowledge
        if(bAccept)
        {
                UDPPut(DHCP_OPTION_ACK_MESSAGE);        
                UDPPut(1);
                UDPPut(DHCP_ACK_MESSAGE);
        }
        else    // Send a NACK
        {
                UDPPut(DHCP_OPTION_ACK_MESSAGE);        
                UDPPut(1);
                UDPPut(DHCP_NAK_MESSAGE);
        }

        // Option: Lease duration
        UDPPut(DHCP_IP_LEASE_TIME);
        UDPPut(4);
        UDPPut((DHCP_LEASE_DURATION>>24) & 0xFF);
        UDPPut((DHCP_LEASE_DURATION>>16) & 0xFF);
        UDPPut((DHCP_LEASE_DURATION>>8) & 0xFF);
        UDPPut((DHCP_LEASE_DURATION) & 0xFF);

        // Option: Server identifier
        UDPPut(DHCP_SERVER_IDENTIFIER); 
        UDPPut(sizeof(IP_ADDR));
        UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR));

        // Option: Subnet Mask
        UDPPut(DHCP_SUBNET_MASK);
        UDPPut(sizeof(IP_ADDR));
        UDPPutArray((BYTE*)&AppConfig.MyMask, sizeof(IP_ADDR));

        // Option: Router/Gateway address
        UDPPut(DHCP_ROUTER);            
        UDPPut(sizeof(IP_ADDR));
        UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR));

        // Option: DNS server address
        UDPPut(DHCP_DNS);
        UDPPut(sizeof(IP_ADDR));
        UDPPutArray((BYTE*)&AppConfig.MyIPAddr, sizeof(IP_ADDR));

        // No more options, mark ending
        UDPPut(DHCP_END_OPTION);

        // Add zero padding to ensure compatibility with old BOOTP relays that discard small packets (<300 UDP octets)
        while(UDPTxCount < 300u)
                UDPPut(0); 

        // Force remote destination address to be the broadcast address, regardless 
        // of what the node's source IP address was (to ensure we don't try to 
        // unicast to 0.0.0.0).
        memset((void*)&UDPSocketInfo[MySocket].remoteNode, 0xFF, sizeof(NODE_INFO));

        // Transmit the packet
        UDPFlush();
}

#endif //#if defined(STACK_USE_DHCP_SERVER)
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3