コード例 #1
0
/*****************************************************************************
  Function:
    static bool ARP_SendIfPkt(NET_CONFIG* pIf, uint16_t oper, uint32_t srcIP, uint32_t dstIP, MAC_ADDR* dstMAC)

  Description:
    Writes an ARP packet to the MAC using the interface pointer for src IP and MAC address.

  Precondition:
    None

  Parameters:

  Return Values:
    true - The ARP packet was generated properly
    false - otherwise


  ***************************************************************************/
static bool ARP_SendIfPkt(NET_CONFIG* pIf, uint16_t oper, uint32_t srcIP, uint32_t dstIP, MAC_ADDR* dstMAC)
{
    ARP_PACKET       packet;
    TCPIP_MAC_HANDLE hMac;


    packet.HardwareType  = HW_ETHERNET;
    packet.Protocol      = ARP_IP;
    packet.MACAddrLen    = sizeof(MAC_ADDR);
    packet.ProtocolLen   = sizeof(IP_ADDR);
    packet.Operation = oper;

    packet.SenderMACAddr = pIf->MyMACAddr;
    packet.SenderIPAddr.Val  = srcIP;
    packet.TargetMACAddr = *dstMAC;
    packet.TargetIPAddr.Val  = dstIP;

    SwapARPPacket(&packet);


    hMac = _TCPIPStackNetToMac(pIf);
    if(!MACIsTxReady(hMac))
    {
        return false;
    }

    MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac));
    MACPutHeader(hMac, &packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(packet));
    MACPutArray(hMac, (uint8_t*)&packet, sizeof(packet));
    MACFlush(hMac);

    return true;
}
コード例 #2
0
/*****************************************************************************
  Function:
    ARP_RESULT ARPProcess(NET_CONFIG* pIf)

  Summary:
    Processes an incoming ARP packet.

  Description:
    Retrieves an ARP packet from the MAC buffer and determines if it is a
    response to our request (in which case the ARP is resolved) or if it
    is a request requiring our response (in which case we transmit one.)

  Precondition:
    ARP packet is ready in the MAC buffer.

  Parameters:
    None

  Return Values:
    ARP_RES_OK      - processing OK.
    ARP_RES_error   - some error occurred
  ***************************************************************************/
ARP_RESULT ARPProcess(NET_CONFIG* pIf)
{
    ARP_PACKET      packet;
    MAC_ADDR        *dstMAC;
    OA_HASH_ENTRY   *hE;
    ARP_CACHE_DCPT  *pArpDcpt;
    int              netIx;
    TCPIP_MAC_HANDLE hMac;
    ARP_RESULT       arpReqRes;

    netIx = _TCPIPStackNetIx(pIf);
    pArpDcpt = arpCache + netIx;
    hMac = _TCPIPStackNetToMac(pIf);

    // Obtain the incoming ARP packet and process
    MACGetArray(hMac, (uint8_t*)&packet, sizeof(packet));
    MACDiscardRx(hMac);
    SwapARPPacket(&packet);

    // Validate the ARP packet
    if ( packet.HardwareType != HW_ETHERNET     ||
            packet.MACAddrLen != sizeof(MAC_ADDR)  ||
            packet.ProtocolLen != sizeof(IP_ADDR) )
    {
        return ARP_RES_OK;
    }
#ifdef TCPIP_STACK_USE_ZEROCONF_LINK_LOCAL
    ARPProcessRxPkt(pIf, &packet);
#endif

    arpReqRes = ARP_RES_OK;
    // Handle incoming ARP packet
    hE = OAHashLookUp(pArpDcpt->cacheDcpt, &packet.SenderIPAddr.Val);
    if(hE != 0)
    {   // we already have this sender and we should update it
        _ARPUpdateEntry(pIf, (ARP_HASH_ENTRY*)hE, &packet.SenderMACAddr);
    }

    while(packet.TargetIPAddr.Val == pIf->MyIPAddr.Val)
    {   // we are the target and we should add to cache anyway
        if(hE == 0)
        {   // not there yet
            arpReqRes = _ARPAddCompleteEntry(pIf, &packet.SenderIPAddr, &packet.SenderMACAddr);
        }

        // Handle incoming ARP operation
        if(packet.Operation == ARP_OPERATION_REQ)
        {
            // ARP packet asking for this host IP address
#ifdef TCPIP_STACK_USE_ZEROCONF_LINK_LOCAL
            /* Fix for Loop-Back suppression:
             * For ZCLL-Claim packets, host should not respond.
             * Check Sender's MAC-address with own MAC-address and
             * if it is matched, response will not be sent back. This
             * was leading to flooding of ARP-answeres */
            if(!memcmp (&packet.SenderMACAddr, &pIf->MyMACAddr, 6))
            {
                SYS_CONSOLE_MESSAGE("Loopback answer suppressed \r\n");
                break;
            }
#endif
#if defined(TCPIP_STACK_USE_AUTO_IP)
            if ((packet.SenderIPAddr.Val == pIf->MyIPAddr.Val) || AutoIPConfigIsInProgress(pIf))
            {
                AutoIPConflict(pIf);
                break;
            }
#endif

            // Need to send a reply to the requestor
#if defined(TCPIP_STACK_USE_AUTO_IP)
            if (AutoIPIsConfigured(pIf))
            {
                dstMAC = &arpBcastAdd;
            }
            else
#endif
            {
                dstMAC = &packet.SenderMACAddr;
            }
            // Send an ARP response to the received request
            if(!ARP_SendIfPkt(pIf, ARP_OPERATION_RESP, (uint32_t)pIf->MyIPAddr.Val, (uint32_t)packet.SenderIPAddr.Val, dstMAC))
            {
                arpReqRes =  ARP_RES_TX_FAILED;
            }
        }
        break;
    }

    return arpReqRes;
}
コード例 #3
0
/*****************************************************************************
  Function:
	void UDPPerformanceTask(NET_CONFIG* pConfig)

  Summary:
	Tests the transmit performance of the UDP module.

  Description:
	This function tests the transmit performance of the UDP module.  At boot,
	this module will transmit 1024 large UDP broadcast packets of 1024 bytes
	each.  Using a packet sniffer, one can determine how long this process 
	takes and calculate the transmit rate of the stack.  This function tests 
	true UDP performance in that it will open a socket, transmit one packet, 
	and close the socket for each loop.  After this initial transmission, the
	module can be re-enabled by holding button 3.
	
	This function is particularly useful after development to determine the
	impact of your application code on the stack's performance.  A before and
	after comparison will indicate if your application is unacceptably
	blocking the processor or taking too long to execute.

  Precondition:
	UDP is initialized.

  Parameters:
	pConfig - network to run on

  Returns:
	None
  ***************************************************************************/
void UDPPerformanceTask(NET_CONFIG* pConfig)
{
	UDP_SOCKET	MySocket;
	NODE_INFO	Remote;
	uint16_t		wTemp;
	static uint32_t dwCounter = 1;

	if((BUTTON3_IO) && (dwCounter > 1024u))
		return;

	// Suppress transmissions if we don't have an Ethernet link so our counter starts correctly at 0x00000001
	if(!MACIsLinked(_TCPIPStackNetToMac(pConfig)))
		return;
	
	#if defined(TCPIP_STACK_USE_DHCP_CLIENT) && defined(DELAY_UDP_PERFORMANCE_TEST)
	{
		static SYS_TICK dwTimer = 0;
		
		// Wait until DHCP module is finished
		if(!DHCPIsBound(pConfig))
		{
			dwTimer = SYS_TICK_Get();
			return;
		}

		// Wait an additional half second after DHCP is finished to let the announce module and any other stack state machines to reach normal operation
		if(SYS_TICK_Get() - dwTimer < SYS_TICK_TicksPerSecondGet()/2)
			return;
	}
	#endif

	// Set the socket's destination to be a broadcast over our IP 
	// subnet
	// Set the MAC destination to be a broadcast
	memset(&Remote, 0xFF, sizeof(Remote));
	
	// Open a UDP socket for outbound transmission
	MySocket = UDPOpen((uint32_t)&Remote,UDP_OPEN_NODE_INFO,0,PERFORMANCE_PORT);
	
	// Abort operation if no UDP sockets are available
	// If this ever happens, incrementing UDP_MAX_SOCKETS in 
	// udp_config.h may help (at the expense of more global memory 
	// resources).
	if(MySocket == INVALID_UDP_SOCKET)
		return;
    UDPSocketSetNet(MySocket, pConfig);

	// Make certain the socket can be written to
	if(!UDPIsPutReady(MySocket))
	{
		UDPClose(MySocket);
		return;
	}
	
	// Put counter value into first 4 bytes of the packet
	UDPPutArray(MySocket, (uint8_t*)&dwCounter, sizeof(dwCounter));
	dwCounter++;
	
	wTemp = UDPPutArray(MySocket, (const uint8_t*)
			"The quick brown fox tried to jump over the yellow dog.  Unfortunately, the yellow dog stood up while the fox was in mid-jump.  As a result, the two collided.  Then, the dog, being the omnivore that it is, ate the quick brown fox.  This line is 256 bytes.\r\n"
			"The quick brown fox tried to jump over the yellow dog.  Unfortunately, the yellow dog stood up while the fox was in mid-jump.  As a result, the two collided.  Then, the dog, being the omnivore that it is, ate the quick brown fox.  This line is 256 bytes.\r\n"
			"The quick brown fox tried to jump over the yellow dog.  Unfortunately, the yellow dog stood up while the fox was in mid-jump.  As a result, the two collided.  Then, the dog, being the omnivore that it is, ate the quick brown fox.  This line is 256 bytes.\r\n"
			"The quick brown fox tried to jump over the yellow dog.  Unfortunately, the yellow dog stood up while the fox was in mid-jump.  As a result, the two collided.  Then, the dog, being the omnivore that it is, ate the quick brown fox.  This line is 252b. \r\n", 1020);

	// Send the packet
	UDPFlush(MySocket);
	
	// Close the socket so it can be used by other modules
	UDPClose(MySocket);
}
コード例 #4
0
void ANNOUNCE_Send(void)
{
    UDP_SOCKET  announceSocket;
    int         netIx;
    uint16_t    dataLen;
    uint16_t    minimumDataLen;
    uint16_t    txLen;
    bool truncated;
    NET_CONFIG * pNetIf;
    ANNOUNCE_LIST_NODE *  node = (ANNOUNCE_LIST_NODE *)announceEvents.head;
    ANNOUNCE_FIELD_PAYLOAD payloadType;
    uint16_t terminatorLen = strlen ((const char *)announceFieldTerminator);

#if defined (TCPIP_STACK_USE_IPV6)
    IPV6_ADDR_STRUCT * addressPointer;
#endif

    while (node != NULL)
    {    
        pNetIf = (NET_CONFIG *)node->handle;

        netIx = TCPIP_STACK_NetIx (pNetIf);

        truncated = false;

        dataLen = ((terminatorLen + 1) * 4) + sizeof (IPV4_ADDR) + sizeof (MAC_ADDR);

        dataLen += strlen(TCPIP_HOSTS_CONFIGURATION[netIx].interface);
        dataLen += strlen((char *)pNetIf->NetBIOSName);
    
        minimumDataLen = dataLen + 1 + terminatorLen;
    
        if(!MACIsLinked(_TCPIPStackNetToMac(pNetIf)))  // Check for link before blindly opening and transmitting (similar to DHCP case)
        {
            return;
        }
    
        announceSocket = UDPOpenClient(IP_ADDRESS_TYPE_IPV4, ANNOUNCE_PORT, 0);
    
        if (announceSocket == INVALID_UDP_SOCKET)
        {
            return;
        }
    
        UDPSocketSetNet (announceSocket, pNetIf);
    
    #if defined (TCPIP_STACK_USE_IPV6)
        addressPointer = (IPV6_ADDR_STRUCT *)ipv6Config[netIx].listIpv6UnicastAddresses.head;
    
        while(addressPointer != NULL)
        {
            dataLen += sizeof (IPV6_ADDR) + 1 + terminatorLen;
            addressPointer = addressPointer->next;
        }
    
        addressPointer = (IPV6_ADDR_STRUCT *)ipv6Config[netIx].listIpv6MulticastAddresses.head;
    
        while(addressPointer != NULL)
        {
            dataLen += sizeof (IPV6_ADDR) + 1 + terminatorLen;
            addressPointer = addressPointer->next;
        }
    #endif
    
        if (dataLen > ANNOUNCE_MAX_PAYLOAD)
        {
            dataLen = ANNOUNCE_MAX_PAYLOAD;
        }
    
        if ((txLen = UDPIsTxPutReady(announceSocket, dataLen)) < dataLen)
        {
            truncated = true;
            if ((txLen = UDPIsTxPutReady(announceSocket, minimumDataLen)) < minimumDataLen)
            {
                UDPClose (announceSocket);
                return;
            }
        }
    
        // Put Mac Address
        payloadType = ANNOUNCE_FIELD_MAC_ADDR;
        UDPPut (announceSocket, payloadType);
        UDPPutArray(announceSocket, (const uint8_t *)&pNetIf->MyMACAddr, sizeof (MAC_ADDR));
        UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen);

        if (truncated)
        {
            payloadType = ANNOUNCE_FIELD_TRUNCATED;
            UDPPut (announceSocket, payloadType);
            UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen);
        }

        // Put Mac Type
        payloadType = ANNOUNCE_FIELD_MAC_TYPE;
        UDPPut (announceSocket, payloadType);
        UDPPutArray(announceSocket, (const uint8_t *)TCPIP_HOSTS_CONFIGURATION[netIx].interface, strlen ((const char *)TCPIP_HOSTS_CONFIGURATION[netIx].interface));
        UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen);

        // Put Host Name
        payloadType = ANNOUNCE_FIELD_HOST_NAME;
        UDPPut (announceSocket, payloadType);
        UDPPutArray(announceSocket, (const uint8_t *)&pNetIf->NetBIOSName, strlen((char*)pNetIf->NetBIOSName));
        UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen);

        // Put IPv4 Address
        payloadType = ANNOUNCE_FIELD_IPV4_ADDRESS;
        UDPPut (announceSocket, payloadType);
        UDPPutArray(announceSocket, (const uint8_t *)&pNetIf->MyIPAddr, sizeof (IP_ADDR));
        UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen);
    
#if defined (TCPIP_STACK_USE_IPV6)
    
        // Put IPv6 unicast addresses
        minimumDataLen = sizeof (IPV6_ADDR) + 1 + terminatorLen;
    
        addressPointer = (IPV6_ADDR_STRUCT *)ipv6Config[netIx].listIpv6UnicastAddresses.head;
    
        payloadType = ANNOUNCE_FIELD_IPV6_UNICAST;

        while(addressPointer != NULL && (UDPIsTxPutReady(announceSocket, minimumDataLen) >= minimumDataLen))
        {
            UDPPut (announceSocket, payloadType);
            UDPPutArray(announceSocket, (const uint8_t *)&addressPointer->address, sizeof (IPV6_ADDR));
            UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen);
            addressPointer = addressPointer->next;
        }
    
        // Put IPv6 multicast listeners    
        addressPointer = (IPV6_ADDR_STRUCT *)ipv6Config[netIx].listIpv6MulticastAddresses.head;
    
        payloadType = ANNOUNCE_FIELD_IPV6_MULTICAST;

        while(addressPointer != NULL && (UDPIsTxPutReady(announceSocket, minimumDataLen) >= minimumDataLen))
        {
            UDPPut (announceSocket, payloadType);
            UDPPutArray(announceSocket, (const uint8_t *)&addressPointer->address, sizeof (IPV6_ADDR));
            UDPPutArray (announceSocket, announceFieldTerminator, terminatorLen);
            addressPointer = addressPointer->next;
        }
#endif
    
        UDPFlush (announceSocket);
    
        UDPClose (announceSocket);

        SingleListRemoveHead(&announceEvents);

        TCPIP_HEAP_Free (announceMemH, node);

        node = (ANNOUNCE_LIST_NODE *)announceEvents.head;

        if (node == NULL)
        {
            announceEventPending = false;
        }
    }
}
コード例 #5
0
ファイル: auto_ip.c プロジェクト: webgou/Equinox-Clock
void AutoIPTasks(NET_CONFIG* pConfig)
{
//    uint8_t i;
    TCPIP_MAC_HANDLE hMac;

//    for (i = 0; i < NETWORK_INTERFACES; i++)
    {
        LoadState(_TCPIPStackNetIx(pConfig));
        hMac = _TCPIPStackNetToMac(pConfig);
        AutoIPClient.flags.bits.bCurrentLinkState = MACIsLinked(hMac);
    	if(AutoIPClient.flags.bits.bCurrentLinkState != AutoIPClient.flags.bits.bLastLinkState)
    	{
    		AutoIPClient.flags.bits.bLastLinkState = AutoIPClient.flags.bits.bCurrentLinkState;
    		if(!AutoIPClient.flags.bits.bCurrentLinkState)
    		{
                AutoIPClient.flags.bits.bConfigureAutoIP = false;
                AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED;
    			pConfig->MyIPAddr.Val = pConfig->DefaultIPAddr.Val;
    			pConfig->MyMask.Val = pConfig->DefaultMask.Val;
    		}
            else
            {
                AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG;
            }
    	}
    
        #if defined (TCPIP_STACK_USE_DHCP_CLIENT)
        if (DHCPIsBound(pConfig))
        {
            AutoIPClient.flags.bits.bConfigureAutoIP = false;
            AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED;
            AutoIPClient.flags.bits.bLastDHCPState = true;
        }
        else
        {
            if (AutoIPClient.flags.bits.bLastDHCPState == true)
            {
                if (AutoIPClient.flags.bits.bCurrentLinkState)
                    AutoIPClient.smAUTOIPState = SM_AUTOIP_INIT_RNG;
            }
            AutoIPClient.flags.bits.bLastDHCPState = false;
        }
        #endif
    
    
        if (AutoIPClient.flags.bits.gDisableAutoIP == true)
        {
            AutoIPClient.flags.bits.bConfigureAutoIP = false;
            AutoIPClient.smAUTOIPState = SM_AUTOIP_DISABLED;
        }
    
    
        switch (AutoIPClient.smAUTOIPState)
        {
            // Default no-AutoIP case
        	case SM_AUTOIP_DISABLED:

                break;
    
            // Initializes the random number generator with a seed based on the MAC address
            case SM_AUTOIP_INIT_RNG:
                AutoIPRandSeed (((uint32_t)pConfig->MyMACAddr.v[0] + ((uint32_t)pConfig->MyMACAddr.v[1] << 8) + \
                        ((uint32_t)pConfig->MyMACAddr.v[2] << 16) + ((uint32_t)pConfig->MyMACAddr.v[3] << 24) + \
                        ((uint32_t)pConfig->MyMACAddr.v[4]) + ((uint32_t)pConfig->MyMACAddr.v[5] << 8)), pConfig);
    
                AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS;
    
            // Check the address to see if it's in use before we write it into NetConfig
            case SM_AUTOIP_CHECK_ADDRESS:
    
                if (AutoIPClient.flags.bits.checkAddress == false)
                {
                    AutoIPClient.flags.bits.checkAddress = true;
    
                    pConfig->MyMask.Val = 0x00000000;
    
                    // Generate a random IP address (based on the MAC address) to try and claim.
                    // Dynamic link-local addresses can fall within the range:
                    // 169.254.1.0 - 169.254.254.255
                    AutoIPClient.packet.TargetIPAddr.byte.MB = AutoIPRand(pConfig) % 256;
                    AutoIPClient.packet.TargetIPAddr.byte.UB = (AutoIPRand(pConfig) % 254) + 1;
                    AutoIPClient.packet.TargetIPAddr.word.LW = 0xFEA9;
    
                    ARPResolve (pConfig, &AutoIPClient.packet.TargetIPAddr);
    
                    AutoIPClient.eventTime = SYS_TICK_Get();
                }
                
                if (!ARPIsResolved (pConfig, &AutoIPClient.packet.TargetIPAddr, &AutoIPClient.packet.TargetMACAddr))
                {
                    if (SYS_TICK_Get() - AutoIPClient.eventTime > SYS_TICK_TicksPerSecondGet())
                    {
                        AutoIPClient.smAUTOIPState = SM_AUTOIP_SETUP_MESSAGE;
                    }
                }
                else
                {
                    AutoIPClient.flags.bits.checkAddress = false;
                }
    
                break;
    
            // Set up an ARP packet
            case SM_AUTOIP_SETUP_MESSAGE:
    
                AutoIPClient.flags.bits.checkAddress = false;
    
                // Set the bConfigureAutoIP flag- This flag will cause an AutoIP conflict
                // if a response packet is received from the address we're trying to claim.
                AutoIPClient.flags.bits.bConfigureAutoIP = true;
    
                // Configure the fields for a gratuitous ARP packet
            	AutoIPClient.packet.Operation            = ARP_OPERATION_REQ;
            
            	AutoIPClient.packet.TargetMACAddr.v[0]   = 0xff;
            	AutoIPClient.packet.TargetMACAddr.v[1]   = 0xff;
            	AutoIPClient.packet.TargetMACAddr.v[2]   = 0xff;
            	AutoIPClient.packet.TargetMACAddr.v[3]   = 0xff;
            	AutoIPClient.packet.TargetMACAddr.v[4]   = 0xff;
            	AutoIPClient.packet.TargetMACAddr.v[5]   = 0xff;
    
                pConfig->MyIPAddr = AutoIPClient.packet.TargetIPAddr;
                pConfig->MyMask.Val = 0x0000FFFF;
            	memcpy(&AutoIPClient.packet.SenderMACAddr, (void*)&pConfig->MyMACAddr, sizeof(AutoIPClient.packet.SenderMACAddr));
                AutoIPClient.packet.HardwareType  = HW_ETHERNET;
                AutoIPClient.packet.Protocol      = ARP_IP;
                AutoIPClient.packet.MACAddrLen    = sizeof(MAC_ADDR);
                AutoIPClient.packet.ProtocolLen   = sizeof(IP_ADDR);
                AutoIPClient.packet.SenderIPAddr.Val  = AutoIPClient.packet.TargetIPAddr.Val;
    
                SwapARPPacket(&AutoIPClient.packet);
    
                // Generate a random delay between 0 and 1 second
                AutoIPClient.randomDelay = ((LFSRRand() % 20) * SYS_TICK_TicksPerSecondGet()) / 20;
                // Store the current time
                AutoIPClient.eventTime = SYS_TICK_Get();
    
                // Set the state to send the ARP packet
                AutoIPClient.smAUTOIPState = SM_AUTOIP_GRATUITOUS_ARP1;
    
                break;
    
            // Send a gratuitous ARP packet to try and claim our address
            case SM_AUTOIP_GRATUITOUS_ARP1:
            case SM_AUTOIP_GRATUITOUS_ARP2:
            case SM_AUTOIP_GRATUITOUS_ARP3:
                // Check to ensure we've passed the delay time
                if (SYS_TICK_Get() - AutoIPClient.eventTime > AutoIPClient.randomDelay)
                {
                	if(!MACIsTxReady(hMac))
                    {
                        break;
                    }
                    // Store the new event time
                    AutoIPClient.eventTime = SYS_TICK_Get();
                    // Generate a new random delay between 1 and 2 seconds
                    AutoIPClient.randomDelay = SYS_TICK_TicksPerSecondGet() + (((LFSRRand() % 20) * SYS_TICK_TicksPerSecondGet()) / 20);
    
                    // Transmit the packet
                	MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac));
    
                    MACPutHeader(hMac, &AutoIPClient.packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(AutoIPClient.packet));
                    MACPutArray(hMac, (uint8_t*)&AutoIPClient.packet, sizeof(AutoIPClient.packet));
                    MACFlush(hMac);
    
                    // Increment the probe iteration or increment to the delay state
                    AutoIPClient.smAUTOIPState++;
                }
                break;
    
            // Delay for 1-2 seconds after sending the third ARP request before
            // entering the configured state
            case SM_AUTOIP_DELAY:
                if (SYS_TICK_Get() - AutoIPClient.eventTime > AutoIPClient.randomDelay)
                    AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED;
                break;
    
            // Configure the module to limit the rate at which packets are sent
            case SM_AUTOIP_RATE_LIMIT_SET:
                AutoIPClient.eventTime = SYS_TICK_Get();
                pConfig->MyIPAddr.Val = pConfig->DefaultIPAddr.Val;
                AutoIPClient.smAUTOIPState = SM_AUTOIP_RATE_LIMIT_WAIT;
                break;
    
            // Ensure that we don't try more than one address every 60 seconds
            case SM_AUTOIP_RATE_LIMIT_WAIT:
                if (SYS_TICK_Get() - AutoIPClient.eventTime > SYS_TICK_TicksPerSecondGet() * 60)
                    AutoIPClient.smAUTOIPState = SM_AUTOIP_CHECK_ADDRESS;
                break;
    
            // Configured state
            case SM_AUTOIP_CONFIGURED:
                AutoIPClient.flags.bits.bConfigureAutoIP = false;
                break;
    
            // Address defense state
            case SM_AUTOIP_DEFEND:
                // Prepare and send an ARP response
            	if(!MACIsTxReady(hMac))
                {
                    break;
                }
                AutoIPClient.packet.Operation     = ARP_OPERATION_RESP;
                AutoIPClient.packet.HardwareType  = HW_ETHERNET;
                AutoIPClient.packet.Protocol      = ARP_IP;
    
                SwapARPPacket(&AutoIPClient.packet);
    
            	MACSetWritePtr(hMac, MACGetTxBaseAddr(hMac));
    
                MACPutHeader(hMac, &AutoIPClient.packet.TargetMACAddr, ETHERTYPE_ARP, sizeof(AutoIPClient.packet));
                MACPutArray(hMac, (uint8_t*)&AutoIPClient.packet, sizeof(AutoIPClient.packet));
                MACFlush(hMac);
    
                AutoIPClient.smAUTOIPState = SM_AUTOIP_CONFIGURED;
                break;
        }
    }
}