2 votos

Error de cálculo de AVR long int

Estoy teniendo algunos problemas con una función( void CheckSum() ) para un cálculo de suma de comprobación.

El problema es que cuando llamo a esa función dentro de otra función llamada ICMP_Frame(), funciona bien. Pero cuando la llamo dentro de otra función IPv4_Frame(), simplemente comete un gran error.

Comienza a dejar todos los valores que son mayores que 0xFFFF.

(en ICMP_Frame() ) 0xc4f1 + 0x6566 = 0x12a57 (esto está bien)

(en IPv4_Frame() )0xc4f1 + 0x6566 = 0x2a57 (esto NO está bien)

#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érlo 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
        }
    }
}

El void CheckSum() debería hacer algo así:

Por ejemplo, considere el hexágono 4500003044224000800600008c7c19acae241e2b (20 bytes de cabecera IP), usando una máquina que utiliza la aritmética estándar del complemento a dos estándar de dos complementos:

Paso 1) 4500 + 0030 + 4422 + 4000 + 8006 + 0000 + 8c7c + 19ac + ae24 + 1e2b = 0002BBCF (suma de 32 bits) /el resultado en IPv4_Frame() es 0000BBCF)/

Paso 2) 0002 + BBCF = BBD1 = 1011101111010001 (complemento a 1 de 16 bits suma de 16 bits, formada por el "carry" de la suma de complemento a 2 de 32 bits)

Paso 3) ~BBD1 = 0100010000101110 = 442E (complemento a 1 de 1's complemento de 16 bits)

Un código más despojado:

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;
}

2voto

nocgod Puntos 16

¡Solución encontrada!

He cambiado la línea de esto:

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

A esto:

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

Que alguien me explique por qué ha servido de algo.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X