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

library

?curdirlinks? - Rev 32

?prevdifflink? - Blame - ?getfile?

/*********************************************************************
 *
 *  Zero Confiruation (Zeroconf) IPV4 Link Local Addressing
 *  Module for Microchip TCP/IP Stack
 *
 *********************************************************************
 * FileName:        ZeroconfLinkLocal.h
 * Dependencies:    IP, ARP
 * Processor:       PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 *                                      Microchip C30 v3.12 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2009-2010 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
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Pradeep Reddy        01 Mar 2009 Initial
 * Pradeep Reddy        12 May 2009 Enhancements and fixes
 * Pradeep Reddy        13 May 2010 Code documentation and cleanup
 * Brad Rex             05 Apr 2010 Updated for MRF24WB0M.
 ********************************************************************/
#define __Zeroconf__Link_Local_C

#include "TCPIP Stack/TCPIP.h"

#define TICK DWORD

#if defined(STACK_USE_ZEROCONF_LINK_LOCAL)
#include "TCPIP Stack/ZeroconfLinkLocal.h"
//#include "ZGCustomize.h"

extern void DisplayIPValue(IP_ADDR IPVal);

/* Constant to cross-check whether
 * DHCP Clinet is configured to use */
#if defined(STACK_USE_DHCP_CLIENT)
const BYTE g_zcll_dhcp_client = 1;
#else
const BYTE g_zcll_dhcp_client = 0;
#endif

/* constants from RFC2937, section 9 */
#define PROBE_WAIT           1 /*second  (initial random delay)              */
#define PROBE_MIN            1 /*second  (minimum delay till repeated probe) */
#define PROBE_MAX            2 /*seconds (maximum delay till repeated probe) */
#define PROBE_NUM            3 /*         (number of probe packets)          */
#define ANNOUNCE_WAIT        2 /*seconds  (delay before announcing)          */
#define ANNOUNCE_NUM         2 /*        (number of announcement packets)    */
#define ANNOUNCE_INTERVAL    2 /*seconds (time between announcement packets) */
#define MAX_CONFLICTS       10 /*        (max conflicts before rate limiting)*/
#define RATE_LIMIT_INTERVAL 60 /*seconds (delay between successive attempts) */
#define DEFEND_INTERVAL     10 /*seconds (min. wait between defensive ARPs)  */

/* compilation constants */
#define IPV4_LLBASE 0xa9fe0100 /* 169.254.1.0 */

/* ARP  States Enum */
typedef enum _ARPState{
        ARPProbe = 0,
        ARPClaim,
        ARPDefend
} ARP_STATE;

/* Link-Local States Enum */
typedef enum _ZeroconfLLState
{
        SM_INIT = 0,
        SM_INTF_NOT_PRESENT,
        SM_INTF_NOT_CONNECTED,
        SM_DHCP_PRESENT,
        SM_ADDR_INIT,
        SM_ADDR_PROBE,
        SM_ADDR_CLAIM,
        SM_ADDR_DEFEND, 
        SM_ADDR_RELEASE,
} ZCLL_STATE;

/* Required for Tracking DHCP events */
typedef enum __zcll_dhcp_substate {
        ZCLL_DHCP_INIT = 0,
        ZCLL_DHCP_PHASE_1,
        ZCLL_DHCP_PHASE_2,
}ZCLL_DHCP_SUBSTATE;

/* ARP-Packet Types defined in RFC 2937 */
typedef enum arp_pkt_type {
        ARP_REQUEST_TYPE = 0,
        ARP_PROBE_TYPE,
        ARP_CLAIM_TYPE,
        ARP_DEFEND_TYPE,
        ARP_RESPONSE_TYPE,
        UNKNOWN_TYPE,
}ARP_PKT_TYPE;

/* Flags for the ZCLL State Machine */
typedef union _ZCLL_FLAGS
{
    struct
    {
        unsigned char bIsIntfPresent : 1;               // Whether or not Interface is present
        unsigned char bIsDHCPPresent : 1;               // Whether or not DHCP Client is enabled & 
                                                                                                // DHCP server is detected
                unsigned char bIsConnected : 1;                 // Indicates if WiFi interface is connected
                unsigned char probe_conflict :1 ;               // Conflict When selecting IP-addr
                unsigned char late_conflict : 1;                // Conflict When using IP-addr
    } bits;
    BYTE Val;
} ZCLL_FLAGS;

/**************** Global Declarations ***************/
ZCLL_STATE zcll_state = SM_INIT;
ZCLL_DHCP_SUBSTATE zcll_dhcp_substate =ZCLL_DHCP_INIT;
static ZCLL_FLAGS zcll_flags = {{0x00}};

static IP_ADDR temp_IP_addr;    // Temporary IP address before checking uniquness
#ifdef STACK_CLIENT_MODE
static MAC_ADDR temp_MAC_addr;  // Temporary MAC address
#endif
static BYTE probe_count = 0;
static BYTE conflict_count = 0; 
static BYTE announce_count = 0;

static BOOL bDefaultIPTried = FALSE;

static CHAR arp_reg_id;

/***************** Forward Declarations **************/
void ZeroconfARPPktNotify (DWORD SenderIPAddr, DWORD TargetIPAddr, 
                           MAC_ADDR* SenderMACAddr, 
                           MAC_ADDR* TargetMACAddr, BYTE op_req);
static struct arp_app_callbacks callbacks = 
{
        .ARPPkt_notify  = ZeroconfARPPktNotify,
};

//rex#if 0
//rextZGVoidReturn 
//rexZeroconfIndicate(tZGU8 type, tZGDataPtr fourByteHeader, tZGDataPtr pBuf, tZGU16 len)
//rex{
//rex    tZGU16 status;
//rex    
//rex    switch(type)
//rex    {
//rex           case kZGMgtIndDisconnect:
//rex           /* A deauth indication occurs when the AP has announced
//rex             * to our chip that the connection is no longer valid.  It becomes
//rex             * the responsibility of the wifiManager to determine what to do
//rex             * in that situation */
//rex                   INFO_ZCLL_PRINT("Zeroconf-Callback: Disconnect Event Notification \r\n");
//rex            zcll_flags.bits.bIsConnected = 0;   
//rex        break;
//rex        
//rex    case kZGMgtIndConnStatus:
//rex    
//rex        status = (fourByteHeader[0] << 8) | fourByteHeader[1];
//rex        if (status == kZGConnStatusFound)
//rex        {
//rex            //APPCXT.bConnLost = 0;
//rex            //APPCXT.bConnFound = 1;
//rex                   zcll_flags.bits.bIsConnected = 1;
//rex        }
//rex        break;
//rex        
//rex    default:
//rex        /* error condition un-recognized type */
//rex        break;
//rex    }
//rex    
//rex}
//rex#endif

DWORD zcll_rand(void)
{
        return TickGet();
}

/***************************************************************
  Function:
        static void ZeroconfStateMachineReset(void)

  Summary:
        Resets Zeroconf's Link-Local state-machine
    
  Description:
        This function resets the state-machine of Link-Local module.
    This is invoked in the initalization and when a address-conflict
    is detected.   

  Parameters:
        None 

  Returns:
        None
  ***************************************************************/
#if 0
#define ZeroconfStateMachineReset() \
{probe_count = zcll_flags.bits.late_conflict = zcll_flags.bits.probe_conflict =0;}
#endif

static void ZeroconfStateMachineReset(BOOL bResetProbeCount)
{
        if (bResetProbeCount)
        {
                probe_count = 0;
        }
        zcll_flags.bits.late_conflict = 0; 
        
        //conflict_count = 0;
        //zcll_flags.bits.probe_conflict = 0;
}


/***************************************************************
  Function:
        void ARPAction(IP_ADDR SrcIPAddr,IP_ADDR DestIPAddr ,BYTE op_req,ARP_STATE ARPAction)

  Summary:
     a).ARPProbe:
          Sends out the ARP-probe packet.
     b).ARPClaim:
          Sends out the ARP-Claim packet.
     c).ARPDefend:
         Sends out the ARP-Defend packet, when a address-conflict is detected.
    
  Description:


    a).ARPProbe:
        This function is used to send out the ARP-Probe packet to check
    the uniquness of selected IP-address in private space(169.254.x.x)

    This function makes use of ARPSendPkt User-API exposed by ARP 
    module. 

    ARP-Probe Packet:
          ARP-Request
          sender IP address: 0.0.0.0
          sender HW address: Self MAC address
          target IP address: <probe addr> (Chosen IP-address 169.254.x.x)
          target HW address: FF:FF:FF:FF:FF:FF
          
    b).ARPClaim:
        This function is used to send out the ARP-Claim packet to finalize
    the uniquness of selected IP-address in private space(169.254.x.x).
    This claim packet is final-step in decision making of selected IP-
    address.

    This function makes use of ARPSendPkt User-API exposed by ARP 
    module. 

    ARP-Probe Packet:
          ARP-Request
          sender IP address: <claim addr> (Chosen IP-address 169.254.x.x)
          sender HW address: Self MAC address
          target IP address: <claim addr> (Chosen IP-address 169.254.x.x)
          target HW address: FF:FF:FF:FF:FF:FF
          
    c).ARPDefend:
        This function is used to send out the ARP-Defend packet to defend
    the selected IP-address. When a conflicting ARP-packet (Probe or
    Claim) is observed on local network ARP-defend packet will be sent
    out to announe its authority of owning IP-address.

    This function makes use of ARPSendPkt User-API exposed by ARP 
    module. 

    ARP-Probe Packet:
          ARP-Response
          sender IP address: <claim addr> (Chosen IP-address 169.254.x.x)
          sender HW address: Self MAC address
          target IP address: <claim addr> (Chosen IP-address 169.254.x.x)
          target HW address: FF:FF:FF:FF:FF:FF

  Parameters:
        None 

  Returns:
        None
  ***************************************************************/

void ARPAction(DWORD SrcIPAddr,DWORD DestIPAddr ,BYTE op_req,ARP_STATE ARPAction)
{
        BOOL rc;

        rc = ARPSendPkt( SrcIPAddr, DestIPAddr,op_req);

#if defined ( INFO_ZCLL )
        if(rc == FALSE)
        {
         switch (ARPAction)
         {
                        case ARPProbe:
                                INFO_ZCLL_PRINT("ARPProbe: Error in sending out ARP-Probe pkt \n");
                            break;
                        case ARPClaim:
                                INFO_ZCLL_PRINT("ARPClaim: Error in sending out ARP-Claim pkt \n");
                            break;
                        case ARPDefend:
                                INFO_ZCLL_PRINT("ARPDefend: Error in sending out ARP-Defend pkt \n");
                            break;
         }              
        }
#endif
}

/***************************************************************
  Function:
        ARP_PKT_TYPE FindARPPktType (DWORD SrcIPAddr, DWORD DestIPAddr, 
                                 BYTE op_req)

  Summary:
        Finds the Type of ARP-Packet based on the Source IP-address,
    Destination IP-address and operation-request.
    
  Description:
        This function is used to find out the ARP-packet type. When ARP
    module passes up a ARP-packet to Zeroconf Link-Local module, it 
    parses contents and finds the packet-type (like ARP-Probe, ARP-
    Claim, ARP-Defend, or generic ARP-request/response)    

  Parameters:
        SrcIPAddr    - Source IP-Address
    DestIPAddr   - Destination IP-Address
    op_req       - Operation-Request (ARP-Request/Response)

  Returns:
        ARP_PKT_TYPE - Type of ARP-Packet (Probe, Claim, Defend or 
                    generic ARP-request/response)
  ***************************************************************/
ARP_PKT_TYPE FindARPPktType (DWORD SrcIPAddr, DWORD DestIPAddr,BYTE op_req)
{
        if(op_req == ARP_REQ)
        {
                if(SrcIPAddr == 0x0)
                        return ARP_PROBE_TYPE;
                else if (SrcIPAddr == DestIPAddr)
                        return ARP_CLAIM_TYPE;
                else 
                        return ARP_REQUEST_TYPE;

        }

        else if(op_req == ARP_RESP)
        {
                if(SrcIPAddr == DestIPAddr)
                        return ARP_DEFEND_TYPE;
                else
                        return ARP_RESPONSE_TYPE;
        }
        
        else
                return UNKNOWN_TYPE;
}
        
/***************************************************************
  Function:
        void ZeroconfARPPktNotify (DWORD SenderIPAddr, DWORD TargetIPAddr, 
                           MAC_ADDR* SenderMACAddr, 
                           MAC_ADDR* TargetMACAddr, BYTE op_req)

  Summary:
        Callback registered with ARP-Module. This gets invoked from ARP-
    module and runs in the same context.
    
  Description:
        This function is registered as a callback with ARP-module to get 
    notified about incoming Packet-events. Based on the type of packet
    received and Link-Local current state, appropriate action will be 
    taken. To find the type of ARP-Packet this function makes use of 
    FindARPPktType routine.

    Primary purpose of this function is to decipher the ARP-Packet rxed
    and check whether its leading to a conflict with the selected IP-
    address.

    Two types of conflicts are defined: Probe-Conflict and Late-Conflict
    If the current state of Link-Local is Probe/Claim and a conflict is
    detected its called "Probe-Conflict"
    If the current state of Link-Local is Defend-state and a conflict is
    detected its called "Late-Conflict"

  Parameters:
        SenderIPAddr    - Sender IP-Address
    TargetIPAddr    - Target IP-Address
    SenderMACAddr   - Sender MAC-Address
    TargetMACAddr   - Target MAC-Address
    op_req          - Operation-Request (ARP-Request/Response)
        
  Returns:
        None
  ***************************************************************/      
void ZeroconfARPPktNotify (DWORD SenderIPAddr, DWORD TargetIPAddr, 
                           MAC_ADDR* SenderMACAddr, 
                           MAC_ADDR* TargetMACAddr, BYTE op_req)
{
        ARP_PKT_TYPE pkt_type;

        pkt_type = FindARPPktType (SenderIPAddr, TargetIPAddr, op_req);

        if(pkt_type == UNKNOWN_TYPE)
                return; // Can't hit this

        switch (zcll_state)
        {
        case SM_ADDR_PROBE:
        case SM_ADDR_CLAIM:
                {
                        switch(pkt_type)
                        {
                        case ARP_PROBE_TYPE:
                        case ARP_CLAIM_TYPE:
                        case ARP_DEFEND_TYPE:
                                if(temp_IP_addr.Val == TargetIPAddr ) // Probe-Conflict
                                {
                                        if(memcmp(SenderMACAddr, &AppConfig.MyMACAddr, 6)) 
                                        {
                                                DEBUG_ZCLL_PRINT("ARPPktNotify: Somebody has initiated " \
                                                        "the procedure to use same Addr.\r\n");

                                                zcll_flags.bits.probe_conflict =1;
                                        }
                                }
                                break;

                        case ARP_RESPONSE_TYPE:
                                /* Some-body has been using probed addr
                                * We need to choose different Address */
                                if(temp_IP_addr.Val == SenderIPAddr) 
                                {
                                        DEBUG_ZCLL_PRINT("ARPPktNotify: Some-body has responded for " \
                                                "probed IP-addr \r\n");

                                        zcll_flags.bits.probe_conflict =1;      
                                }
                                break;
                        default:
                                break;
                        }
                }
                break;

        case SM_ADDR_DEFEND:
                {
                        if(AppConfig.MyIPAddr.Val == SenderIPAddr)
                        {
                                if(memcmp(SenderMACAddr, &AppConfig.MyMACAddr, 6)) 
                                {
                                        DEBUG_ZCLL_PRINT("ARPPktNotify: Some-one has started using" \
                                                " our IP-address \r\n");

                                        zcll_flags.bits.late_conflict = 1;
                                }
                        }
                }
                break;

        default:
                break; // Nothing to do in other states
        }

}

/***************************************************************
  Function:
        static void zcll_seed_random()

  Summary:
        Seeds the Random-Number generator with Last four bytes of MAC-
    address & current-time.
    
  Description:
        This function is used to seed the random-number generator. To get
    better uniquness in random-number, last four bytes of MAC-address 
    is used as seed. Though the MAC-address is unique, the first 3
    bytes represent the manufacturer, which will be same for all the 
    Network-Interface cards from same manufacturer.

    To add more randomness the current-time is also added as seed. The
    current-time alone can't be used as seed. Because there's a fair
    chance that all the devices in local-area network might be powered
    up at the same-time, then which leads to conflict.

    So combination of MAC-Address and current-time is good seed for a
    random-number generator.
        
  Parameters:
        None

  Returns:
        None
  ***************************************************************/
#if 0
static void zcll_seed_random()
{
        DWORD_VAL temp;
        DWORD tick = TickGet();
        temp.v[3] = AppConfig.MyMACAddr.v[2];
        temp.v[2] = AppConfig.MyMACAddr.v[3];
        temp.v[1] = AppConfig.MyMACAddr.v[4];
        temp.v[0] =     AppConfig.MyMACAddr.v[5];
        srand( temp.Val + tick ); 
}
#endif

/***************************************************************
  Function:
        void ZeroconfLLInitialize(void)

  Summary:
        Initialization routine for Zeroconf Link-Local state-machine.
    
  Description:
    This is initialization function for Zeroconf Link-Local and 
    invoked from initialization portion of Main-function. 

    This function registers with ARP-module to get notifications
    about the incoming packets. Checks whether the WiFi MAC is 
    connected to an Access-Point or not.

  Parameters:
        None

  Returns:
        None
  ***************************************************************/
void ZeroconfLLInitialize(void)
{
        /* ARP is core module for IPv4 LL protocol.
         * Register event callbacks with ARP, to get 
         * notified. */
        arp_reg_id = ARPRegisterCallbacks(&callbacks);
        if(arp_reg_id <0)
        {
                WARN_ZCLL_PRINT("ZeroconfLLInitialize: ARP Callback registration Failed!!! \r\n");
                return;
        }
                        
        /* Check for the presence of Interface 
     * Currently there's no way to check the
     * presence of interface. So always true. 
     * Later it needs to replaced by actual
     * condition */
        if(0)
        {
                zcll_state = SM_INTF_NOT_PRESENT;
                return;
        }

        if(!MACIsLinked())
        {
                zcll_state = SM_INTF_NOT_CONNECTED;
                return;
        }
        
        /* check if DHCP-Client is enabled & able to detect DHCP-Server */
        if(g_zcll_dhcp_client)
        {
                zcll_state = SM_DHCP_PRESENT;
                zcll_dhcp_substate = ZCLL_DHCP_INIT;
                return;
                
        }
        
        zcll_state = SM_ADDR_INIT;
        /* setup random number generator
        * we key this off the MAC-48 HW identifier
        * the first 3 octets are the manufacturer
        * the next 3 the serial number
        * we'll use the last four for the largest variety
        */
        //zcll_seed_random();
                        
        return;
}

/***************************************************************
  Function:
        void ZeroconfLLProcess(void)

  Summary:
        Initialization routine for Zeroconf Link-Local state-machine.
    
  Description:
    This is Polled from Main-Application & Designed to support 
    co-operative multi-tasking. This needs to retrun to Main, 
    if we have to wait for Longer durations.

    This is the main function for Zeroconf's Link-Local and takes 
    the actions accoding to current-state and event-notifications
    from ARP-Module.

  Parameters:
        None

  Returns:
        None
  ***************************************************************/


void ZeroconfLLProcess(void)
{
        static TICK event_time; // Internal Timer, to keep track of events
        static unsigned char time_recorded; // Flag to indicate event_time is loaded
        static unsigned char defended; // Flag to indicate, whether or not defended earlier
        static TICK random_delay;

        if(!MACIsLinked())
        {
                zcll_state = SM_INTF_NOT_CONNECTED;
        }

        switch(zcll_state)
        {                       
        case SM_INIT:
                WARN_ZCLL_PRINT("SM_INIT: Wrong state \r\n");
                break;

        case SM_INTF_NOT_PRESENT:
                DEBUG_ZCLL_PRINT("SM_INTF_NOT_PRESENT: Intf not detected \r\n");
                break;

        case SM_INTF_NOT_CONNECTED:

                //DEBUG_ZCLL_MESG(zeroconf_dbg_msg,"SM_INTF_NOT_CONNECTED \r\n");
                //DEBUG_ZCLL_PRINT((char*)zeroconf_dbg_msg);

                if(!MACIsLinked())
                {
                        //INFO_ZCLL_PRINT((char *)("MAC is not connected yet \r\n"));
                        return;
                }
                else
                {
                        /* Interface is connected now */
                        zcll_state = SM_DHCP_PRESENT;
                        zcll_dhcp_substate = ZCLL_DHCP_INIT;
                        time_recorded = 0;
                        event_time = 0;
                        defended = 0;
                }

        case SM_DHCP_PRESENT:
                {
                        //DEBUG_ZCLL_PRINT("SM_INTF_DHCP_PRESENT \r\n");

                        if(!g_zcll_dhcp_client)
                        {
                                zcll_state = SM_ADDR_INIT;
                        }
#if defined(STACK_USE_DHCP_CLIENT)
                        else
                        {

                                switch(zcll_dhcp_substate)
                                {
                                case ZCLL_DHCP_INIT:

                                        DEBUG_ZCLL_PRINT("ZCLL_DHCP_INIT: Entered \r\n");
                                        DEBUG_ZCLL_MESG((char *) zeroconf_dbg_msg,"TICKS_PER_SECOND = %ld \r\n", 
                                                ((TICK) (TICKS_PER_SECOND)));
                                        DEBUG_ZCLL_PRINT((char *) zeroconf_dbg_msg);
                                        if(!AppConfig.Flags.bIsDHCPEnabled)
                                        {
                                                DEBUG_ZCLL_PRINT("ZCLL_DHCP_INIT: Enabling DHCP client \r\n");
                                                DHCPEnable((BYTE) 0); //DHCPEnable();
                                                time_recorded = 0;      
                                        }       
                                        /* Start a Fisrt-phase Timer with 1 min Timeout
                                        * to allow DHCP-client to IP-address DHCP-ser */

                                        AppConfig.MyIPAddr.Val = 0;

                                        event_time = TickGet();
                                        time_recorded = 1;
                                        random_delay = (TICK) (ZEROCONF_LINK_LOCAL_DHCP_TIMEOUT * \
                                                TICK_SECOND );
                                        zcll_dhcp_substate = ZCLL_DHCP_PHASE_1;
                                        INFO_ZCLL_PRINT("Waiting for DHCP-Client to Get IP-addr from" \
                                                " DHCP-server..... \r\n");

                                        return;

                                case ZCLL_DHCP_PHASE_1:

                                        if(time_recorded) 
                                        {
                                                if(TickGet() - event_time < random_delay)
                                                {
                                                        //if(DHCPFlags.bits.bDHCPServerDetected && 
                                                        //   DHCPFlags.bits.bIsBound)
                                                        if (DHCPIsServerDetected((BYTE) 0) &&
                                                                DHCPIsBound((BYTE) 0))
                                                        {
                                                                INFO_ZCLL_PRINT("DHCP IP-address received. No Zeroconf " \
                                                                        "Link-Local required !! \r\n");
                                                                INFO_ZCLL_MESG(zeroconf_dbg_msg,"DHCP IP-Addr: " \
                                                                        "%d.%d.%d.%d \r\n",
                                                                        AppConfig.MyIPAddr.v[0], 
                                                                        AppConfig.MyIPAddr.v[1],
                                                                        AppConfig.MyIPAddr.v[2], 
                                                                        AppConfig.MyIPAddr.v[3]);
                                                                INFO_ZCLL_PRINT((char *)zeroconf_dbg_msg);
                                                                DisplayIPValue(AppConfig.MyIPAddr); // LCD Disaply

                                                                time_recorded = 0; // Cancel Timer
                                                                zcll_dhcp_substate = ZCLL_DHCP_PHASE_2;
                                                                return;

                                                        }
                                                        return;
                                                }
                                                // First Time out. Disable DHCP & Use Link-Local
                                                time_recorded = 0; // Reset Timer Flag
                                                event_time = 0;  // Cancel Timer

                                                break;
                                        }
                                        else
                                        {
                                                DEBUG_ZCLL_PRINT("ERROR !! Can't Enter this DHCP " \
                                                        "Substate without timer \r\n");
                                                break;
                                        }

                                case ZCLL_DHCP_PHASE_2:

                                        /* Able to get an IP-address from DHCP,
                                        * constantly moniotor for Validity. If
                                        * found invalid, move back to phase-1. */

                                        //if(   DHCPFlags.bits.bIsBound)
                                        if (DHCPIsBound((BYTE) 0)) 
                                        {
                                                return;
                                        }
                                        else
                                        {
                                                if(!AppConfig.Flags.bIsDHCPEnabled)
                                                {
                                                        /* Somebody else had disabled DHCP client.
                                                        * Goto Link-Local addressing */
                                                        DEBUG_ZCLL_PRINT("ZCLL_DHCP_PHASE_2: Externel module " \
                                                                "disabled DHCP-Client \r\n");
                                                        break;
                                                }

                                                temp_IP_addr.Val = 0x0;
                                                time_recorded = 0;
                                                zcll_dhcp_substate = ZCLL_DHCP_INIT;
                                                return;                                                 
                                        }

                                default:

                                        DEBUG_ZCLL_PRINT("ERROR !! Invalid DHCP Substate \r\n");
                                        break;
                                }
                        }

                        // No break. Fall through

                        // The following is commented out, to implement the behavior described in
                        // RFC 3927, section 2.11.
                        // In particular, IPv4LL should not "stop the DHCP client from attempting
                        // to acquire a new IP address".

                        #if defined(DISREGARD_RFC3927_SECTION_2_11)
                        /* Disable DHCP Client, as it's not able to get an IP */
                        INFO_ZCLL_PRINT("Disabling DHCP-Client. Going to use Link-Local \r\n");
                        DHCPDisable((BYTE) 0);
                        #endif

#else
                        INFO_ZCLL_PRINT("DHCP-Client is not present. Going to use Link-Local \r\n");
#endif
                        zcll_state = SM_ADDR_INIT;
                        /* Not yet seeded in init routine */
                        /* setup random number generator
                        * we key this off the MAC-48 HW identifier
                        * the first 3 octets are the manufacturer
                        * the next 3 the serial number
                        * we'll use the last four for the largest variety
                        */
                        //zcll_seed_random();
                        DEBUG0_ZCLL_MESG(zeroconf_dbg_msg,"SM_DHCP_PRESENT --> SM_ADDR_INIT \r\n");
                        DEBUG0_ZCLL_PRINT((char*)zeroconf_dbg_msg);

                        // No break. Fall through
                }

        case SM_ADDR_INIT:

                ZeroconfStateMachineReset(FALSE);
                conflict_count = 0;
                AppConfig.MyIPAddr.Val = 0x0;
                DisplayIPValue(AppConfig.MyIPAddr); // LCD Display

#ifdef STACK_CLIENT_MODE
                ARPInit();
#endif
                probe_count = 0;

                zcll_state = SM_ADDR_PROBE;
                INFO_ZCLL_PRINT("ADDR_INIT --> ADDR_PROBE \r\n");

                // No break. Fall through

        case SM_ADDR_PROBE:

                //DEBUG_ZCLL_PRINT("SM_ADDR_PROBE \r\n");

                switch ( zgzc_wait_for(&random_delay, &event_time, &time_recorded) )
                {
                case ZGZC_STARTED_WAITING:

                        if (probe_count == 0)
                        {
                                // First probe. Wait for [0 ~ PROBE_WAIT] seconds before sending the probe.

                                //random_delay = (TICK)(((zcll_rand()) % (PROBE_WAIT) * TICK_SECOND));
                                //if (random_delay == 0) random_delay = (TICK) TICK_SECOND;

                                random_delay = (TICK) (zcll_rand() % (PROBE_WAIT * TICK_SECOND));

                                DEBUG0_ZCLL_MESG(zeroconf_dbg_msg,"PROBE_WAIT Random Delay [%d]: %ld secs \r\n",
                                        probe_count,
                                        random_delay);
                        }
                        else if (probe_count < PROBE_NUM)
                        {
                                // Subsequent probes. Wait for [PROBE_MIN ~ PROBE_MAX] seconds before sending the probe.

                                // random_delay = (TICK) ( (((zcll_rand() % (PROBE_MAX-PROBE_MIN+1))+PROBE_MIN) * TICKS_PER_SECOND) + (TICKS_PER_SECOND>>3) );
                                // Added a little bit more delay to pass conformance test.
                                
                                random_delay = (TICK) ( (zcll_rand() % ((PROBE_MAX-PROBE_MIN) * TICKS_PER_SECOND) ) +
                                        (PROBE_MIN * TICKS_PER_SECOND) );

                                DEBUG0_ZCLL_MESG(zeroconf_dbg_msg,"PROBE Random Delay [%d]: %ld ticks \r\n",
                                        probe_count,
                                        random_delay);
                        }
                        else
                        {
                                // Completed PROBE_NUM of probes. Now wait for ANNOUNCE_WAIT seconds to determine if
                                // we can claim it.

                                random_delay = (TICK) (ANNOUNCE_WAIT * TICK_SECOND);
                                DEBUG0_ZCLL_MESG(zeroconf_dbg_msg,"ANNOUNCE_WAIT delay [%d]: %ld ticks\r\n",
                                        probe_count,
                                        random_delay /*TICK_SECOND */);
                        }

                        DEBUG0_ZCLL_PRINT((char*)zeroconf_dbg_msg);

                        // Intentional fall-through

                case ZGZC_KEEP_WAITING:

                        // Not Completed the delay proposed
                        return;
                }

                // Completed the delay required

                DEBUG0_ZCLL_MESG(zeroconf_dbg_msg,"   delay: %ld ticks " \
                        "completed \r\n", random_delay);
                DEBUG0_ZCLL_PRINT((char *)zeroconf_dbg_msg);

                if(zcll_flags.bits.probe_conflict)
                {
                        /* Conflict with selected address */
                        INFO_ZCLL_PRINT("Probe Conflict-1 Detected. Need to select diff addr \r\n");
                        ZeroconfStateMachineReset(FALSE);
                        temp_IP_addr.Val = 0x0;

                        conflict_count++;
                        AppConfig.MyIPAddr.Val = 0x0;
                }
#ifdef STACK_CLIENT_MODE
                else if((conflict_count == 0) && temp_IP_addr.Val && (ARPIsResolved(&temp_IP_addr, &temp_MAC_addr)) ) 
                {
                        if(!memcmp (&temp_MAC_addr, &AppConfig.MyMACAddr, 6) )
                        {
                                DEBUG0_ZCLL_PRINT("SM_ADDR_PROBE: Resolved with our address only. " \
                                        "Rare Case !!!! \r\n");
                        }
                        else
                        {
                                /* Conflict with selected address */
                                INFO_ZCLL_PRINT("Probe Conflict-2 Detected. Need to select diff addr \r\n");
                                ZeroconfStateMachineReset(FALSE);
                                temp_IP_addr.Val = 0x0;

                                conflict_count++;
                                AppConfig.MyIPAddr.Val = 0x0;
                        }
                }
#endif

                if ((zcll_flags.bits.probe_conflict == 1) ||
                        (!bDefaultIPTried))
                {
                        /*
                        * Pick random IP address in IPv4 link-local range
                        * 169.254.1.0/16 is the allowed address range however 
                        * 169.254.0.0/24 and 169.254.255.0/24 must be excluded, 
                        * which removes 512 address from our 65535 candidates. 
                        * That leaves us with 65023 (0xfdff) 
                        */

                        // Need to start/restart the probe procedure.
                        probe_count = 0;

                        if ((!bDefaultIPTried) &&
                                (AppConfig.DefaultIPAddr.v[0] == 169) && 
                                (AppConfig.DefaultIPAddr.v[1] == 254) &&
                                (AppConfig.DefaultIPAddr.v[2] != 0) &&
                                (AppConfig.DefaultIPAddr.v[2] != 255))
                        {
                                // First probe, and the default IP is a valid IPv4LL address.
                                // Use it.

                                temp_IP_addr.Val = swapl(AppConfig.DefaultIPAddr.Val);
                                bDefaultIPTried = TRUE;
                        }
                        else
                        {
                                temp_IP_addr.Val = (IPV4_LLBASE | ((abs(zcll_rand()) % 0xfdff) ));
                        }                

                        INFO_ZCLL_MESG(zeroconf_dbg_msg,"Picked IP-Addr [%d]: %d.%d.%d.%d \r\n",
                                probe_count,
                                temp_IP_addr.v[3],temp_IP_addr.v[2],
                                temp_IP_addr.v[1],temp_IP_addr.v[0]);
                        INFO_ZCLL_PRINT((char *)zeroconf_dbg_msg);

                        temp_IP_addr.Val = swapl((DWORD) temp_IP_addr.Val);
                }

                // ToDo: check the max probe limit and probing rate
                if((zcll_flags.bits.probe_conflict == 1) || (probe_count < PROBE_NUM))
                {

                        zcll_flags.bits.probe_conflict = 0;
                        ARPAction(AppConfig.MyIPAddr.Val, temp_IP_addr.Val, ARP_REQ,ARPProbe);
                        probe_count++;

                        DEBUG0_ZCLL_MESG(zeroconf_dbg_msg, "Sending ARP [%d]\r\n", probe_count);
                        DEBUG0_ZCLL_PRINT((char *)zeroconf_dbg_msg);

                        break;
                }

                // No conflict detected ...

                if(probe_count >= PROBE_NUM) 
                {               
                        zcll_state = SM_ADDR_CLAIM;
                        announce_count = 0;

                        INFO_ZCLL_PRINT("ADDR_PROBE --> ADDR_CLAIM \r\n");

                        return;
                }

                break;

        case SM_ADDR_CLAIM:

                switch ( zgzc_wait_for(&random_delay, &event_time, &time_recorded) )
                {
                case ZGZC_STARTED_WAITING:
                        if (announce_count == 0)
                        {
                                // First announcement is immediate. We have passed the ANNOUNCE_WAIT in
                                // PROBE state already.

                                random_delay = 0;
                        }
                        else 
                        {
                                // Subsequent announcements need to wait ANNOUNCE_INTERVAL seconds
                                // before sending the announcement.

                                random_delay = (TICK)(ANNOUNCE_INTERVAL * TICK_SECOND);
                        }
                        // Intentional fall-through

                case ZGZC_KEEP_WAITING:

                        // Not Completed the delay proposed
                        return;
                }

                // Completed the delay required

                DEBUG0_ZCLL_MESG(zeroconf_dbg_msg,"ANNOUNCE delay: %ld ticks completed \r\n", random_delay);
                DEBUG0_ZCLL_PRINT((char *)zeroconf_dbg_msg);

                if ( announce_count < ANNOUNCE_NUM )
                {
                        ARPAction(temp_IP_addr.Val,temp_IP_addr.Val,ARP_REQ,ARPClaim);
                        announce_count++;

                        DEBUG0_ZCLL_MESG(zeroconf_dbg_msg, "Sending ANNOUNCEMENT [%d]\r\n", announce_count);
                        DEBUG0_ZCLL_PRINT((char *)zeroconf_dbg_msg);
                }
                else 
                {
                        // Claim it. Goto DEFEND state

                        AppConfig.MyIPAddr = temp_IP_addr;
                        zcll_state = SM_ADDR_DEFEND;
                        DisplayIPValue(AppConfig.MyIPAddr);
                        INFO_ZCLL_MESG(zeroconf_dbg_msg,"\r\n******** Taken IP-Addr: " \
                                "%d.%d.%d.%d ******** \r\n",
                                AppConfig.MyIPAddr.v[0], AppConfig.MyIPAddr.v[1], 
                                AppConfig.MyIPAddr.v[2],AppConfig.MyIPAddr.v[3]);
                        INFO_ZCLL_PRINT((char *)zeroconf_dbg_msg);
                        INFO_ZCLL_PRINT("ADDR_CLAIM --> ADDR_DEFEND \r\n");
                }

                break;

        case SM_ADDR_DEFEND:

                //DEBUG_ZCLL_PRINT("SM_ADDR_DEFEND \r\n");

                if( zcll_flags.bits.late_conflict)
                {
                        if (!defended)
                        {
                                zcll_flags.bits.late_conflict = 0;
                                INFO_ZCLL_PRINT("CONFLICT DETECTED !!! \r\n");

                                INFO_ZCLL_PRINT("Defending the Self Address once \r\n");
                                ARPAction(AppConfig.MyIPAddr.Val, AppConfig.MyIPAddr.Val,ARP_RESP,ARPDefend); 

                                defended = 1;
                        }
                        else
                        {
                                // We are not allowed to defend another conflict during an active defended period

                                INFO_ZCLL_PRINT("Releasing the IP-Address because of multiple Conflicts \r\n");

                                zcll_state = SM_ADDR_RELEASE;

                                defended = 0;
                                event_time = 0;
                                random_delay = 0;

                                INFO_ZCLL_PRINT("ADDR_DEFEND --> ADDR_RELEASE \r\n");
                                break;
                        }
                }

                if (defended)
                {
                        switch ( zgzc_wait_for(&random_delay, &event_time, &time_recorded) )
                        {
                        case ZGZC_STARTED_WAITING:

                                random_delay = (TICK)(DEFEND_INTERVAL * TICK_SECOND);
                                DEBUG0_ZCLL_MESG(zeroconf_dbg_msg,"DEFEND_INTERVAL Delay : %ld ticks\r\n",
                                        random_delay/*TICK_SECOND */);
                                DEBUG0_ZCLL_PRINT((char *)zeroconf_dbg_msg);

                                // Intentional fall-through

                        case ZGZC_KEEP_WAITING:

                                // Not Completed the delay proposed
                                return;
                        }

                        // Completed the delay required

                        DEBUG0_ZCLL_MESG(zeroconf_dbg_msg,"ANNOUNCE delay: %ld ticks " \
                                "completed \r\n", random_delay);
                        DEBUG0_ZCLL_PRINT((char *)zeroconf_dbg_msg);

                        defended = 0;
                }

                break;

        case SM_ADDR_RELEASE:

                INFO_ZCLL_PRINT("ADDR_RELEASE --> ADDR_INIT\r\n");

                AppConfig.MyIPAddr.Val = 0x00;
                
                // Need New Addr
                temp_IP_addr.Val = (IPV4_LLBASE | ((abs(zcll_rand()) % 0xfdff) ));
                temp_IP_addr.Val = swapl((DWORD) temp_IP_addr.Val);

                zcll_state = SM_ADDR_INIT;
                time_recorded = 0;
                defended = 0;
                event_time = 0;
                break;

        default:
                break;  
        }
}               
#endif //#if defined(STACK_USE_ZERCONF_LINK_LOCAL)



{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3