2
\$\begingroup\$

I'm having some trouble with a function( void CheckSum() ) for a checksum calculation.

The problem is, that when I call up that function inside another function called ICMP_Frame(), it works fine. But when I call it up in another function IPv4_Frame(), it simply makes a huge mistake.

It starts to drop all the values that are bigger than 0xFFFF.

expl.: (in ICMP_Frame() ) 0xc4f1 + 0x6566 = 0x12a57 (this is ok)

(in IPv4_Frame() )0xc4f1 + 0x6566 = 0x2a57 (this is NOT ok)

#include <define.h>                     
#include <ENC28J60.h>

// az #include <define.h>   tartalmazza a többi (saját) headert, pl.: SPI.h, USART.h, ADC.h

unsigned char   myIP[4]             =   {192,   168,    0,      11};
unsigned char   myMAC[6]            =   {0x00,  0x04,   0xA3,   0xAA,   0xBB,   0xCC};  // Microchip's first 3bytes(OUI) is 00-04-3A

unsigned char   SourceMAC[6]        =   {0,0,0,0,0,0};
unsigned char   SourceIP[4]         =   {0,0,0,0};

unsigned char   DestinationMAC[6]   =   {0,0,0,0,0,0};
unsigned char   DestinationIP[4]    =   {0,0,0,0};



unsigned int i,x, cnt, temp, tmp, ethertype, transport_layer, package_length;
unsigned char package, RX_BUF[1538]={},TX_BUF[1538]={}, Type[2]={}, Next_Packet_Pointer[2] = {}, Receive_Status_Vector[4] = {};


void ENC28J60_TX_Packet(unsigned char array[], unsigned char control) // control egy vezérlő byte az ENC-nek
{
    if(ENC28J60_RD(ECON1) & TXRTS)
    {
        USART0_TX_String("waiting for TX to complete");
    }
    else
    {
        ENC28J60_BANK_SEL(BANK0);
        ENC28J60_CS();
        ENC28J60_CMD(WCR,EWRPTL);
        SPIWR(0);
        SPIWR(16);
        ENC28J60_DS();

        ENC28J60_CS();
        SPIWR(WBM);
        SPIWR(control);
        for(i=0;i<package_length;i++)
        {
            SPIWRD(array[i]);
        }
        ENC28J60_DS();

        ENC28J60_CS();
        ENC28J60_CMD(WCR,ETXNDL);
        SPIWR(i);
        SPIWR(16);
        ENC28J60_DS();

        ENC28J60_BFS(TXRTS);
    }
}

void ENC28J60_RX_Packet(unsigned char array[])
{
    ENC28J60_CS();
    SPIWR(RBM);
    //  reading next packet pointer (NPP) and Recieve Status Vector (RSV)
    Next_Packet_Pointer[0]      =   SPIWRD(DUMMY);
    Next_Packet_Pointer[1]      =   SPIWRD(DUMMY);
    Receive_Status_Vector[0]    =   SPIWRD(DUMMY);
    Receive_Status_Vector[1]    =   SPIWRD(DUMMY);
    Receive_Status_Vector[2]    =   SPIWRD(DUMMY);
    Receive_Status_Vector[3]    =   SPIWRD(DUMMY);

    package_length=((Receive_Status_Vector[1]<<8)+Receive_Status_Vector[0]);                    //  merging RSV byte 0 and 1 into integer (Byte Count)
    if(package_length%2 != 0)                                                               //  if it's odd
    {
        package_length++;                                                                   //  add +1
    }
    for(i = 0;i<package_length;i++)
    {
        array[i]    =   SPIWRD(DUMMY);
    }
    ENC28J60_DS();

    ENC28J60_CS();
    ENC28J60_CMD(BFS,ECON2);
    SPIWR(PKTDEC);
    ENC28J60_DS();

    ENC28J60_BANK_SEL(BANK0);
    ENC28J60_CS();
    ENC28J60_CMD(WCR,ERXRDPTL);
    SPIWR(Next_Packet_Pointer[0]);                                              //  ERXRDPTL
    SPIWR(Next_Packet_Pointer[1]);                                              //  ERXRDPTH
    ENC28J60_DS();
}

void MAC_Frame(unsigned char array[], unsigned int type)
{
    for(i=0;i<6;i++)
    {
        array[i] =  DestinationMAC[i];
    }
    for(i=6;i<12;i++)
    {
        array[i] =  myMAC[i-6];
    }
    array[12] = type>>8;
    array[13] = type;
    package_length = 14;
}

void CheckSum(unsigned char array[], unsigned int type)
{
    //  http://en.wikipedia.org/wiki/IPv4#Header_Checksum
    //  http://en.wikipedia.org/wiki/IPv4_header_checksum

    unsigned long int checksum = 0;
    unsigned int y = 0;
    if(type == ICMPv4)
    {
        i = 34;                 //  ICMPv4 frame kezdete a csomagban
        y = 74;                 //  ill a frame vége
    }
    else if(type == IPv4)
    {
        i = 14;                 //  IPv4 frame kezdete a csomagban
        y = 34;                 //  ill a frame vége
    }

    //  checksum printelése {
    USART0_TX_String("Checksum: ");
    itoa(checksum, StringA, 16);
    USART0_TX_String(StringA);
    USART0_TXD(13);
    USART0_TXD(10);
    //  checksum printelése }

    for(i=i;i<y;i+=2)
    {
        checksum += ((array[i]<<8) | array[i+1]);                   // a for ciklusban csak ez a lényeg
        //checksum += array[i+1];

        // az adott 2 byte (array[i] és array[i+1]) printelése  {
        USART0_TX_String("byte: ");
        itoa(i, StringA, 10);
        USART0_TX_String(StringA);
        USART0_TXD(9);

        if(array[i] < 0x10)
        {
            USART0_TX_String("0");
        }
        itoa(array[i], StringA, 16);
        USART0_TX_String(StringA);
        if(array[i+1] < 0x10)
        {
            USART0_TX_String("0");
        }
        itoa(array[i+1], StringA, 16);
        USART0_TX_String(StringA);
        USART0_TXD(9);
        ltoa(checksum, StringA, 16);
        USART0_TX_String(StringA);
        USART0_TXD(13);
        USART0_TXD(10);
        // az adott 2 byte (array[i] és array[i+1]) printelése  }

    }

    //  checksum printelése felosztva 2db integeré  {
    USART0_TX_String("Checksum_L:   ");
    itoa((checksum), StringA, 16);
    USART0_TX_String(StringA);
    USART0_TXD(13);
    USART0_TXD(10);
    USART0_TX_String("Checksum_H:   ");
    itoa((checksum>>16), StringA, 16);
    USART0_TX_String(StringA);
    USART0_TXD(13);
    USART0_TXD(10);
    //  checksum printelése felosztva 2db integeré  }

    //  long int konvertálása sima int-é, majd az érték invertálása
    checksum = ((checksum & 0x0000FFFF) + ((checksum>>16) & 0x0000FFFF));
    checksum = ~checksum;


    USART0_TX_String("Checksum: ");
    ltoa(checksum, StringA, 16);
    USART0_TX_String(StringA);
    USART0_TXD(13);
    USART0_TXD(10);

    //   a kapott checksum beilesztése
    if(type == IPv4)
    {
        checksum -=2;                       //   IPv4 esetén egy kompenzálás/foltozás
        array[24] = (checksum>>8);
        array[25] = checksum;
    }

    else if(type == ICMPv4)
    {
        array[36] = (checksum>>8);
        array[37] = checksum;
    }
}

void IPv4_Frame(unsigned char array[])
{
    array[14] = 0x45;                       //  Version and IHL
    array[15] = 0x00;                       //  DSCP and ECN
    array[16] = 0x00;                       //  Total Length
    array[17] = 0x3c;                       //  Total Length
    array[18] = RX_BUF[18];             //  Identification
    array[19] = RX_BUF[19];             //  Identification
    array[20] = 0x00;                       //  Flags and Fragments
    array[21] = 0x00;                       //  Fragments
    array[22] = 0x40;                       //  Time To Live
    array[23] = 0x01;                       //  Protocol
    array[24] = 0x00;                       //  Header Checksum
    array[25] = 0x00;                       //  Header Checksum

    for(i=26;i<30;i++)
    {
        array[i] = myIP[i-26];              //  Sender Hardware Address
    }

    for(i=30;i<34;i++)
    {
        array[i] = DestinationIP[i-30]; //  Sender Hardware Address
    }
    CheckSum(array,IPv4);                   //  CheckSum rutin meghívása itt

    package_length = 34;
}

void ARP_Frame(unsigned char array[])
{
    array[14] = 0;                          //  Hardware Type
    array[15] = 1;                          //  Hardware Type
    array[16] = 8;                          //  Protocol Type
    array[17] = 0;                          //  Protocol Type
    array[18] = 6;                          //  Hardware Address Length
    array[19] = 4;                          //  Protocol Address Length
    array[20] = 0;                          //  Operation
    array[21] = 2;                          //  Operation

    for(i=22;i<29;i++)
    {
        array[i] = myMAC[i-22];         //  Sender Hardware Address
    }

    for(i=28;i<32;i++)
    {
        array[i] = myIP[i-28];              //  Sender Protocol Address
    }

    for(i=32;i<38;i++)
    {
        array[i] = DestinationMAC[i-32];    //  Target Hardware Address
    }

    for(i=38;i<42;i++)
    {
        array[i] = DestinationIP[i-38];     //  Target Protocol Address
    }
    package_length = 42;
}

void ICMP_Frame(unsigned char array[])
{
    array[34] = 0;              //  Type
    array[35] = 0;              //  Code
    array[36] = 0;              //  Checksum
    array[37] = 0;              //  Checksum
    array[38] = RX_BUF[38]; //  ID
    array[39] = RX_BUF[39]; //  ID
    array[40] = RX_BUF[40]; //  Seq
    array[41] = RX_BUF[41]; //  Seq

    for(i=42;i<74;i++)
    {
        array[i] = RX_BUF[i];
    }

    CheckSum(array,ICMPv4);     //  CheckSum rutin meghívása itt
    package_length = 74;
}

void Process_Package(unsigned char array[])                 // array[] ez itt a RX_BUF[]
{
    ethertype = ((array[12]<<8)+array[13]);
    if(ethertype == ARP)
    {
        for(unsigned char a = 0;a<4;a++)
        {
            DestinationIP[a] = array[a+38];
        }
        if(DestinationIP[0] == myIP[0] && DestinationIP[1] == myIP[1] && DestinationIP[2] == myIP[2] && DestinationIP[3] == myIP[3])
        {
            for(unsigned char a = 0;a<6;a++)
            {
                DestinationMAC[a]   = array[a+6];
            }
            for(unsigned char a = 0;a<4;a++)
            {
                DestinationIP[a] = array[a+28];
            }
            MAC_Frame(TX_BUF,ARP);
            ARP_Frame(TX_BUF);
            ENC28J60_TX_Packet(TX_BUF,0);               //  csoamg küldése
        }
    }

    else if(ethertype == IPv4)
    {
        for(unsigned char a = 0;a<4;a++)
        {
            DestinationIP[a] = array[a+30];
        }
        if(DestinationIP[0] == myIP[0] && DestinationIP[1] == myIP[1] && DestinationIP[2] == myIP[2] && DestinationIP[3] == myIP[3])
        {
            for(unsigned char a = 0;a<4;a++)
            {
                DestinationIP[a] = array[a+26];
            }
            for(unsigned char a = 0;a<6;a++)
            {
                DestinationMAC[a] = array[a+6];
            }

            MAC_Frame(TX_BUF,IPv4);
            IPv4_Frame(TX_BUF);                     //  CheckSum rutin használata itt (itt nem jó)

            transport_layer = array[23];
            if(transport_layer == TCP)
            {

            }

            else if(transport_layer == UDP)
            {

            }

            else if(transport_layer == ICMPv4)
            {
                ICMP_Frame(TX_BUF);                 //  CheckSum rutin és itt (itt ok)
                ENC28J60_TX_Packet(TX_BUF,0);       //  csoamg küldése
            }
        }
    }

    else if(ethertype == IPv6)
    {
        if(transport_layer == ICMPv6)
        {

        }
    }

}

int main (void)
{
/*
AVR clock Prescaler,UART, SPI, ENC28J60 Inicializálások (ezek jók)
*/

    while(1)
    {

        ENC28J60_BANK_SEL(BANK1);                   //  BANK1 oszlop kiválasztása az ENC-n
        package = ENC28J60_RD(EPKTCNT);             //  olvasatlan csomagok száma
        if(package!=0)                              //  van-e olvasatlan csomag
        {
            ENC28J60_RX_Packet(RX_BUF);             //  csomag beolvasása
            Process_Package(RX_BUF);                //  csomag feldolgozása
        }
    }
}

The void CheckSum() should do something like this:

For example, consider Hex 4500003044224000800600008c7c19acae241e2b (20 bytes IP header), using a machine which uses standard two's complement arithmetic:

Step 1) 4500 + 0030 + 4422 + 4000 + 8006 + 0000 + 8c7c + 19ac + ae24 + 1e2b = 0002BBCF (32-bit sum) /the result in IPv4_Frame() is 0000BBCF)/

Step 2) 0002 + BBCF = BBD1 = 1011101111010001 (1's complement 16-bit sum, formed by "end around carry" of 32-bit 2's complement sum)

Step 3) ~BBD1 = 0100010000101110 = 442E (1's complement of 1's complement 16-bit sum)

A more stripped down code:

void CheckSum(unsigned char array[], unsigned int type)
{
    //  http://en.wikipedia.org/wiki/IPv4#Header_Checksum
    //  http://en.wikipedia.org/wiki/IPv4_header_checksum

    unsigned long int checksum = 0;
    unsigned int y = 0;
    if(type == ICMPv4)
    {
        i = 34;                 //  
        y = 74;                 //
    }
    else if(type == IPv4)
    {
        i = 14;                 //  
        y = 34;                 //  
    }

    for(i=i;i<y;i+=2)
    {
        checksum += ((array[i]<<8) | array[i+1]);// <<<< Problem is here!?!?
    }

    checksum = ((checksum & 0x0000FFFF) + ((checksum>>16) & 0x0000FFFF));
    checksum = ~checksum;

    if(type == IPv4)
    {
        array[24] = (checksum>>8);
        array[25] = checksum;
    }

    else if(type == ICMPv4)
    {
        array[36] = (checksum>>8);
        array[37] = checksum;
    }
}

void IPv4_Frame(unsigned char array[])
{
    array[14] = 0x45;                       //  Version and IHL
    array[15] = 0x00;                       //  DSCP and ECN
    array[16] = 0x00;                       //  Total Length
    array[17] = 0x3c;                       //  Total Length
    array[18] = RX_BUF[18];             //  Identification
    array[19] = RX_BUF[19];             //  Identification
    array[20] = 0x00;                       //  Flags and Fragments
    array[21] = 0x00;                       //  Fragments
    array[22] = 0x40;                       //  Time To Live
    array[23] = 0x01;                       //  Protocol
    array[24] = 0x00;                       //  Header Checksum
    array[25] = 0x00;                       //  Header Checksum

    for(i=26;i<30;i++)
    {
        array[i] = myIP[i-26];              //  Sender Hardware Address
    }

    for(i=30;i<34;i++)
    {
        array[i] = DestinationIP[i-30]; //  Sender Hardware Address
    }
    CheckSum(array,IPv4);                   //

    package_length = 34;
}

void ICMP_Frame(unsigned char array[])
{
    array[34] = 0;              //  Type
    array[35] = 0;              //  Code
    array[36] = 0;              //  Checksum
    array[37] = 0;              //  Checksum
    array[38] = RX_BUF[38]; //  ID
    array[39] = RX_BUF[39]; //  ID
    array[40] = RX_BUF[40]; //  Seq
    array[41] = RX_BUF[41]; //  Seq

    for(i=42;i<74;i++)
    {
        array[i] = RX_BUF[i];
    }

    CheckSum(array,ICMPv4);     //  
    package_length = 74;
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Okay, I'm not reading that. Point out the calculations that are incorrect. \$\endgroup\$ – Ignacio Vazquez-Abrams Sep 12 '14 at 14:19
  • \$\begingroup\$ Can you post the generated assembly for the the correct and incorrect function calls? \$\endgroup\$ – Matt Young Sep 12 '14 at 14:33
  • 1
    \$\begingroup\$ You need to trim this down to the minimum set of code that demonstrates the problem. BTW, the correct term is "function", not "macro". A macro is something that's created by a #define preprocessor statement. This is important because the semantics of functions and macros are very different. \$\endgroup\$ – Dave Tweed Sep 12 '14 at 15:16
  • \$\begingroup\$ THX for the corrections! I'm still new at programing terms. Sorry don't know how to generate an assembly for it. I'm using WinAVR, if this helps... \$\endgroup\$ – Balázs Bagi Sep 12 '14 at 17:55
  • \$\begingroup\$ Yes. If I change void CheckSum(unsigned char array[], unsigned int type) to void CheckSum(unsigned char* array, unsigned int type) the same error happens. \$\endgroup\$ – Balázs Bagi Sep 12 '14 at 18:16
2
\$\begingroup\$

Solution found!

I've changed the line from this:

checksum += ((array[i]<<8) | array[i+1]);

To this:

 checksum += ((unsigned int)(array[i]<<8) | (unsigned int)array[i+1]);

Someone please explain why this helped?

\$\endgroup\$
  • \$\begingroup\$ I was literally about to ask about that :-) It is because each element of array[...] is only 8 bits, so array[i]<<8 should shift the bits beyond the size of an unsigned char, and always give 0. When you tell the compiler to treat the 8 bit number as a 16 bit number, it will not lose any data bits when it does <<8. \$\endgroup\$ – gbulmer Sep 12 '14 at 19:46
  • \$\begingroup\$ No, the <<8 result in int expression, but that has only 16 bit on AVR including a sign bit. You probably wanted to use array[i] << 8U. \$\endgroup\$ – Turbo J Sep 13 '14 at 13:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.