Example #1
0
BOOL    MACRxbufGetHdr(MAC_ADDR *remote, BYTE* type)
{
    /*
     * This marks that all future accesses to MACRxbufGet and MACPut
     * be applied to Receive buffer.
     */
    bIsRxActive = TRUE;

    if ( RxBuffer.PacketCount )
    {

        /*
         * Set up packet access index.
         */
        RxBuffer.CallerAccess = RxBuffer.CurrentPacket;

        RxBuffer.CallerAccess++;
        if ( RxBuffer.CallerAccess >= MAX_SLIP_BUFFER_SIZE )
            RxBuffer.CallerAccess = 0;


        /*
         * Handle modem commands differently.
         */
        if ( RxBuffer.Data[RxBuffer.CallerAccess] == 'A' )
        {
            /*
             * Once a modem command is detected, we are not interested
             * in detail.
             */
            MACRxbufDiscard();

            /*
             * Mark TxBuffer for Modem String.
             * This will make sure that Transmit ISR does nottransmit END
             * at the end.
             */
            TxBuffer.Flags.bits.bIsModemString = TRUE;

            /*
             * Since this special handling does not follow standard
             * SLIP buffer logic, we will setup all required variables
             * manually.
             */
            TxBuffer.Length = 4;
            TxBuffer.CallerAccess = 0;

            /*
             * Remember to use transmit buffer for MACPut
             */
            bIsRxActive = FALSE;

            /*
             * Now load modem response.
             */
            MACPut('O');
            MACPut('K');
            MACPut('\r');
            MACPut('\n');

            /*
             * Transmit it.
             */
            MACFlush();
        }
        else
        {
            /*
             * This was not a modem command.
             * It must be IP packet.  Mark it accordingly and return.
             */
            *type = MAC_IP;

            return TRUE;
        }
    }
    return FALSE;
}
Example #2
0
/**
 * Check if the MAC Receive Buffer has any received packets.
 * Reads the following data from the next available packet in the RX buffer: <ul>
 *  <li> The MAC 4 bytes RX packet header (status, nex receive packet, length) </li>
 *  <li> The 14 byte Ethernet header </li></ul>
 * Once a data packet is fetched by calling MACRxbufGetHdr, the complete data
 * packet must be fetched (using MACRxbufGet) and discarded (using MACRxbufDiscard).
 * Users cannot call MACRxbufGetHdr multiple times to receive multiple packets
 * and fetch data later on.
 *
 * @param[out] remote   Pointer to a MAC_ADDR structure. This function will write the MAC address of the
 *                      node who sent this packet to this structure
 * @param[out] type     Pointer to byte. This function will write the type of header to this variable.
 *                      Can be ETHER_IP, ETHER_ARP or MAC_UNKNOWN
 *
 * @return              True if RX Buffer contained a packet and it's header was read, False if not
 *
 */
BOOL MACRxbufGetHdr(MAC_ADDR *remote, BYTE* type)
{
    NE_PREAMBLE header;
    BYTE NICWritePtr;
    BYTE NICReadPtr;
    WORD_VAL temp;

    *type = MAC_UNKNOWN;

    //Read CURR and BNDY registers = RX Buffer's GET and PUT pointers
    NICPut(CMDR, 0x60);             //Set page 1
    NICWritePtr = NICGet(CURRP);    //Curr is the RX Buffer's PUT pointer
    NICPut(CMDR, 0x20);             //Reset to page 0
    NICReadPtr = NICGet(BNRY);      //Get BNRY pointer

    // Reset NIC if overrun has occured.
    if ( NICGet(ISR) & 0x10 )
    {
        BYTE resend;

        #if (DEBUG_MAC >= LOG_ERROR)
        debugPutMsg(3); //@mxd:3:Overrun error! Reseting MAC!
        #endif

        // Save TXP bit
        resend = NICGet(CMDR) & 0x04;

        //Issue STOP command to NIC and delay 2ms
        NICPut(CMDR, 0x21);
        DelayMs(2);

        //Clear Remote Byte count registers
        NICPut(RBCR0, 0);
        NICPut(RBCR1, 0);

        // TXP bit set?
        if (resend)
           // No re-send if Packet Transmitted or Transmit Error bit is set
           resend = !(NICGet(ISR) & 0x0A);

        //Put NIC in loopback mode and issue start command
        NICPut(TCR, 0x02);
        NICPut(CMDR, 0x22); // HM: Modified, changed to 22 to re-start NIC

        // Empty ring buffer completely
        MACCurrRxbuf = NICWritePtr;
        MACRxbufDiscard();

        //Reset ISR by writing FF to it
        NICPut(ISR, 0xff);

        //Take NIC out of loopback mode
        NICPut(TCR, 0x00);

        //Resend the packet
        if(resend)
           NICPut(CMDR, 0x26);
        return FALSE;
    }

    //Is there something in the buffer
    if ( NICWritePtr != NICReadPtr )
    {
        temp.v[1] = NICReadPtr; //Pointer to RAM page, is MSB of address
        temp.v[0] = 0;          //LSB is 0
        NICSetAddr(temp.Val);

        //Read the following from the current MAC RX Buffer:
        // - The MAC 4 bytes RX packet header (status, nex receive packet, length)
        // - The 14 byte Ethernet header
        MACRxbufGetArray((BYTE*)&header, sizeof(header));

        // Validate packet length and status as.
        if ( header.Status.PRX && (header.ReceivedBytes >= MINFRAMEC) && (header.ReceivedBytes <= MAXFRAMEC) &&
             (header.NextPacketPointer < RXSTOP) && (header.NextPacketPointer >= RXSTART) )
        {
            header.Type.Val = swaps(header.Type.Val);

            memcpy((void*)remote->v, (void*)header.SourceMACAddr.v, sizeof(*remote));

            if ( (header.Type.v[1] == 0x08) && ((header.Type.v[0] == ETHER_IP) || (header.Type.v[0] == ETHER_ARP)) )
                *type = header.Type.v[0];

            MACCurrRxbuf = NICReadPtr;   //Set MACCurrRxbuf with page address of current RX Buffer
            return TRUE;
        }

        //ERROR!!! Invalid packet received!
        #if (DEBUG_MAC >= LOG_ERROR)
        debugPutMsg(4); //@mxd:4:Invalid Packet Error!
        #endif

        //Ring now contains garbage
        MACCurrRxbuf = NICWritePtr; // Empty ring buffer completely
        MACRxbufDiscard();
    }
    return FALSE;

}
Example #3
0
/**
 * This FSM checks for new incoming packets, and routes it to appropriate
 * stack components. It also performs timed operations.
 *
 * This function must be called periodically called
 * to make sure that timely response.
 *
 * @preCondition    StackInit() is already called.
 *
 * side affect:     Stack FSM is executed.
 */
void StackTask(void)
{
    static NODE_INFO remoteNode;
    static WORD dataCount;

#if defined(STACK_USE_ICMP)
    static BYTE data[MAX_ICMP_DATA_LEN];
    static WORD ICMPId;
    static WORD ICMPSeq;
#endif
    IP_ADDR destIP;     //Is filled with the Destination IP address contained in the IP header


    union
    {
        BYTE MACFrameType;
        BYTE IPFrameType;
        ICMP_CODE ICMPCode;
    } type;


    BOOL lbContinue;


    lbContinue = TRUE;
    while( lbContinue )
    {
        lbContinue = FALSE;

        switch(smStack)
        {
        case SM_STACK_IDLE:
        case SM_STACK_MAC:

            //Check if the MAC RX Buffer has any data, and if it does, read the header.
            //Get the next header from the NIC. The node who sent it's address will be copied to 
            //'remoteNode.MACAddr'.
            if ( !MACRxbufGetHdr(&remoteNode.MACAddr, &type.MACFrameType) )
            {
                //Header was NOT read if MACRxbufGetHdr returned FALSE

                #if defined(STACK_USE_DHCP)
                    //If DHCP is enabled AND MAC is not linked yet, set our IP to 0
                    if (STACK_IS_DHCP_ENABLED)
                    {
                        if ( !MACIsLinked() )
                        {
                            #if (DEBUG_STACKTSK >= LOG_INFO)
                            debugPutMsg(1); //@mxd:1:DHCP Enabled but MAC not linked yet - set IP to 0.0.0.0
                            #endif
                            
                            //IP address must be 0.0.0.0 before DHCP has obtained a valid IP address
                            MY_IP_BYTE1 = 0;
                            MY_IP_BYTE2 = 0;
                            MY_IP_BYTE3 = 0;
                            MY_IP_BYTE4 = 0;

                            stackFlags.bits.bInConfigMode = TRUE;
                            DHCPReset();
                        }
                    }
                #endif

                break;
            }

            lbContinue = TRUE;
            if ( type.MACFrameType == MAC_IP ) {
                smStack = SM_STACK_IP;
                #if (DEBUG_STACKTSK >= LOG_DEBUG)
                debugPutMsg(2); //@mxd:2:Reading MAC IP header
                #endif
            }
            else if ( type.MACFrameType == MAC_ARP ) {
                smStack = SM_STACK_ARP;
                #if (DEBUG_STACKTSK >= LOG_DEBUG)
                debugPutMsg(3); //@mxd:3:Reading MAC ARP header
                #endif
            }
            else {
                MACRxbufDiscard();
                #if (DEBUG_STACKTSK >= LOG_WARN)
                debugPutMsg(4); //@mxd:4:Unknown MAC header read, MAC Frame Type = 0x%x
                debugPutByteHex(type.MACFrameType);
                #endif
            }
            break;

        case SM_STACK_ARP:
            lbContinue = FALSE;
            if ( ARPProcess() )
                smStack = SM_STACK_IDLE;
            break;

        case SM_STACK_IP:
            if ( IPGetHeader(&destIP,  /* Get Destination IP Address as received in IP header */
                             &remoteNode,
                             &type.IPFrameType,
                             &dataCount) )
            {
                lbContinue = TRUE;
                if ( type.IPFrameType == IP_PROT_ICMP )
                {
                    smStack = SM_STACK_ICMP;

#if defined(STACK_USE_IP_GLEANING)
                    if ( stackFlags.bits.bInConfigMode )
                    {
                        /*
                         * Accoriding to "IP Gleaning" procedure, when we receive an ICMP packet
                         * with a valid IP address while we are still in configuration mode,
                         * accept that address as ours and conclude configuration mode.
                         */
                        if ( destIP.Val != 0xffffffff )
                        {
                            stackFlags.bits.bInConfigMode    = FALSE;
                            MY_IP_BYTE1                 = destIP.v[0];
                            MY_IP_BYTE2                 = destIP.v[1];
                            MY_IP_BYTE3                 = destIP.v[2];
                            MY_IP_BYTE4                 = destIP.v[3];

#if defined(STACK_USE_DHCP)
                            /*
                             * If DHCP and IP gleaning is enabled at the
                             * same time, we must ensuer that once we have
                             * IP address through IP gleaning, we abort
                             * any pending DHCP requests and do not renew
                             * any new DHCP configuration.
                             */
                            DHCPAbort();
#endif
                        }
                    }
#endif
                }

#if defined(STACK_USE_TCP)
                else if ( type.IPFrameType == IP_PROT_TCP )
                    smStack = SM_STACK_TCP;
#endif

#if defined(STACK_USE_UDP)
                else if ( type.IPFrameType == IP_PROT_UDP )
                    smStack = SM_STACK_UDP;
#endif

                else
                {
                    lbContinue = FALSE;
                    MACRxbufDiscard();

                    smStack = SM_STACK_IDLE;
                }
            }
            else
            {
                MACRxbufDiscard();
                smStack = SM_STACK_IDLE;
            }
            break;

#if defined(STACK_USE_UDP)
        case SM_STACK_UDP:
            //tempLocalIP.v[0] = MY_IP_BYTE1;
            //tempLocalIP.v[1] = MY_IP_BYTE2;
            //tempLocalIP.v[2] = MY_IP_BYTE3;
            //tempLocalIP.v[3] = MY_IP_BYTE4;
            if ( UDPProcess(&remoteNode, &destIP, dataCount) )
                smStack = SM_STACK_IDLE;
            lbContinue = FALSE;
            break;
#endif

#if defined(STACK_USE_TCP)
        case SM_STACK_TCP:
            //tempLocalIP.v[0] = MY_IP_BYTE1;
            //tempLocalIP.v[1] = MY_IP_BYTE2;
            //tempLocalIP.v[2] = MY_IP_BYTE3;
            //tempLocalIP.v[3] = MY_IP_BYTE4;
            //Will return TRUE if TCPProcess finished it's task, else FALSE
            if ( TCPProcess(&remoteNode, &destIP, dataCount) )
                smStack = SM_STACK_IDLE;
            lbContinue = FALSE;
            break;
#endif

        case SM_STACK_ICMP:
            smStack = SM_STACK_IDLE;

#if defined(STACK_USE_ICMP)
            if ( dataCount <= (MAX_ICMP_DATA_LEN+9) )
            {
                if ( ICMPGet(&type.ICMPCode,
                             data,
                             (BYTE*)&dataCount,
                             &ICMPId,
                             &ICMPSeq) )
                {
                    if ( type.ICMPCode == ICMP_ECHO_REQUEST )
                    {
                        lbContinue = TRUE;
                        smStack = SM_STACK_ICMP_REPLY;
                    }
                    else
                    {
                        smStack = SM_STACK_IDLE;
                    }
                }
                else
                {
                    smStack = SM_STACK_IDLE;
                }
            }
#endif
            MACRxbufDiscard();
            break;

#if defined(STACK_USE_ICMP)
        case SM_STACK_ICMP_REPLY:
            if ( ICMPIsTxReady() )
            {
                ICMPPut(&remoteNode,
                        ICMP_ECHO_REPLY,
                        data,
                        (BYTE)dataCount,
                        ICMPId,
                        ICMPSeq);

                smStack = SM_STACK_IDLE;
            }
            break;
#endif

        }

    }

#if defined(STACK_USE_TCP)
    // Perform timed TCP FSM.
    TCPTick();
#endif


#if defined(STACK_USE_DHCP)
    /*
     * DHCP must be called all the time even after IP configuration is discovered.
     * DHCP has to account lease expiration time and renew the configuration time.
     */
    DHCPTask();

    if ( DHCPIsBound() )
        stackFlags.bits.bInConfigMode = FALSE;
#endif

    //Perform routine MAC tasks
    MACTask();
}
Example #4
0
/**
 * Only one IP message can be received. Caller may not transmit and receive
 * a message at the same time.
 *
 * @preCondition    MACRxbufGetHdr() == TRUE
 *
 * @param localIP   Local node IP Address (Destination IP Address) as received in current IP header.
 *                  If this information is not required caller may pass NULL value.
 * @param remote    Remote node info
 * @param protocol  Current packet protocol
 * @param len       Length of IP data. For example, if TCP is contained in this IP
 *                  packet, this will be = TCP Header length + TCP Data Length
 *
 * @return          TRUE, if valid packet was received <br>
 *                  FALSE otherwise
 */
BOOL IPGetHeader(IP_ADDR *localIP,
                 NODE_INFO *remote,
                 BYTE *protocol,
                 WORD *len)
{
    WORD_VAL    ReceivedChecksum;
    WORD_VAL    CalcChecksum;
    WORD        checksums[2];
    IP_HEADER   header;
    BYTE        optionsLen;
#define MAX_OPTIONS_LEN     (20)            // As per RFC 791.
    BYTE        options[MAX_OPTIONS_LEN];

    //Read IP header. The data is read from the current MAC RX Buffer
    MACRxbufGetArray((BYTE*)&header, sizeof(header));

    //Write out ID of received IP header
#if (DEBUG_IP >= LOG_DEBUG)
    debugPutMsg(1);     //@mxd:1:Received IP header with ID=0x%x%x
    //Write HEX WORD value of tmp
    debugPutByteHex(header.Identification.v[0]);
    debugPutByteHex(header.Identification.v[1]);
#endif

    // Make sure that this IPv4 packet.
    if ( (header.VersionIHL & 0xf0) != IP_VERSION )
    {
        goto IPGetHeader_Discard;
    }

    /*
     * Calculate options length in this header, if there is any.
     * IHL is in terms of numbers of 32-bit DWORDs; i.e. actual
     * length is 4 times IHL.
     */
    optionsLen = ((header.VersionIHL & 0x0f) << 2) - sizeof(header);

    /*
     * If there is any option(s), read it so that we can include them
     * in checksum calculation.
     */
    if ( optionsLen > MAX_OPTIONS_LEN )
    {
        goto IPGetHeader_Discard;
    }

    if ( optionsLen > 0 ) {
        //Read options data. The data is read from the current MAC RX Buffer
        MACRxbufGetArray(options, optionsLen);
    }

    // Save header checksum; clear it and recalculate it ourselves.
    ReceivedChecksum.Val = header.HeaderChecksum.Val;
    header.HeaderChecksum.Val = 0;

    // Calculate checksum of header including options bytes.
    checksums[0] = ~CalcIPChecksum((BYTE*)&header, sizeof(header));

    // Calculate Options checksum too, if they are present.
    if ( optionsLen > 0 )
        checksums[1] = ~CalcIPChecksum((BYTE*)options, optionsLen);
    else
        checksums[1] = 0;

    CalcChecksum.Val  = CalcIPChecksum((BYTE*)checksums,
                                       2 * sizeof(WORD));

    // Network to host conversion.
    SwapIPHeader(&header);

    // Make sure that checksum is correct and IP version is supported.
    if ( ReceivedChecksum.Val != CalcChecksum.Val   ||
            (header.VersionIHL & 0xf0) != IP_VERSION )

    {
        // Bad/Unknown packet. Discard it.
        goto IPGetHeader_Discard;
    }

    /*
     * If caller is intrested, return destination IP address
     * as seen in this IP header.
     */
    if ( localIP )
        localIP->Val    = header.DestAddress.Val;

    remote->IPAddr.Val  = header.SourceAddress.Val;
    *protocol           = header.Protocol;
    *len                = header.TotalLength.Val - optionsLen -  sizeof(header);

    return TRUE;

IPGetHeader_Discard:
    MACRxbufDiscard();
    return FALSE;

}