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