|
| Codeblocks free C++ IDE. |
หลังจากที่แนะนำบอร์ด AVRnet ไปแล้ว บทความนี้จะอธิบายถึงการคำนวณค่า checksum ในโปรโตคอล IP, ICMP, TCP ว่ามีการคำนวณอย่างไร โดยผมจะใช้ฟังก์ชั่น software_checksum เป็นตัวอย่างสำหรับการคำนวณ
ค่า checksum นี้ มีไว้สำหรับตรวจสอบความถูกต้องของข้อมูลที่ส่งไป ฝ่ายที่ส่งข้อมูลจะทำการคำนวณค่า checksum แล้วใส่ค่า checksum ลงไปใน header ของแต่ละโปรโตคอล เมื่อฝ่ายรับข้อมูล รับข้อมูลมาแล้วจะนำเอาค่า checksum นี้มาตรวจสอบข้อมูลที่รับมาว่าถูกต้องหรือไม่
WORD software_checksum(BYTE *rxtx_buffer, WORD len, DWORD sum)
{
// build the sum of 16bit words
while(len>1)
{
sum += 0xFFFF & (*rxtx_buffer<<8|*(rxtx_buffer+1));
rxtx_buffer+=2;
len-=2;
}
// if there is a byte left then add it (padded with zero)
if (len)
{
sum += (0xFF & *rxtx_buffer)<<8;
}
// now calculate the sum over the bytes in the sum
// until the result is only 16bit long
while (sum>>16)
{
sum = (sum & 0xFFFF)+(sum >> 16);
}
// build 1's complement:
return( (WORD) sum ^ 0xFFFF);
}
Function arguments
- BYTE *rxtx_buffer เป็น pointer ที่ชี้ไปที่บัฟเฟอร์ โดยจะชี้ไปที่ตำแหน่งแรกของข้อมูลที่ต้องการนำมาคำนวณค่า checksum เช่น&rxtx_buffer[ IP_P ]
- WORD len ขนาดของข้อมูลที่ต้องการนำมาคำนวณค่า checksum (เป็น bytes) เช่น sizeof(IP_HEADER) ขนาดของข้อมูลจะเท่ากับขนาดของ IP header
- DWORD sum เป็นค่าเริ่มต้นของค่า checksum ตัวแปลนี้จะใช้งานก็ต่อเมื่อ ต้องการคำนวณค่า checksum ของโปรโตคอล TCP เท่านั้น สำหรับโปรโตคอล IP, ICMP ตัวแปลนี้จะต้องเป็น 0
Return value
- ค่าที่ส่งกลับจากฟังก์ชั่นนี้จะเป็นค่า checksum ที่คำนวณได้
การทำงานของฟังก์ชั่น
- ฟังก์ชั่นจะคำนวณค่า checksum แบบ 16-bits จนกว่าขนาดของข้อมูล (len ) จะน้อยกว่า 1-byte จึงหยุดคำนวณค่า checksum แล้วมาตรวจสอบว่ายังมีข้อมูลเหลืออีกหรือไม่
// build the sum of 16bit words
while(len>1)
{
sum += 0xFFFF & (*rxtx_buffer<<8|*(rxtx_buffer+1));
rxtx_buffer+=2;
len-=2;
}
ถ้ายังมีข้อมูลเหลืออีก 1-byte ให้เพิ่ม low byte เข้าไป ค่าใน low byte จะเป็น 0x00 แล้วนำข้อมูลที่เหลือไปคำนวณค่า checksum ต่อ.
// if there is a byte left then add it (padded with zero)
if (len)
{
sum += (0xFF & *rxtx_buffer)<<8;
}
ถ้าค่า checksum ที่ได้มีความยาวมากกว่า 16-bits ให้นำ 16-bits บน ( 16..31 ) มาบวกกับ 16-bits ล่างอีกที ทำแบบนี้จนกว่าผลลัพธ์ที่ได้เหลือเพียง 16-bits.
// now calculate the sum over the bytes in the sum
// until the result is only 16bit long
while (sum>>16)
{
sum = (sum & 0xFFFF)+(sum >> 16);
}
นำค่า checksum ที่ได้มาทำ 1's complement แล้วส่งค่า checksum กลับไป
// build 1's complement:
return( (WORD) sum ^ 0xFFFF);
ค่า checksum ของโปรโตคอล IP คือข้อมูลขนาด 16-bits ที่ได้จากการทำ 1's complement ของการบวกข้อมูลแบบ 16-bits ก่อนที่จะคำนวณค่า checksum ทุกครั้ง ในช่อง checksum จะต้องเป็นศูนย์ ก่อนเสมอ, ข้อมูลที่นำมาคำนวณจะเริ่มจาก address แรกของ IP Header (0x0E) ไปจนถึง address สุดท้ายของ IP Header (0x21) ดังรูปตัวอย่าง.
ตัวอย่างการคำนวณค่า checksum ของ IP Header.
45 00
+ 00 34 = 4534
+ 48 18 = 8d4c
+ 40 00 = cd4c
+ 40 06 = 10d52
+ 00 00 = 10d52
+ 0a 01 = 11753
+ 01 4c = 1189f
+ 0a 01 = 122a0
+ 01 01 = 123a1
23a1 + 0001 = 23a2
นำ 23a2 มาทำ 1's complement = dc5d

รูปตัวอย่างของ IP checksum
ค่า checksum ของโปรโตคอล ICMP เป็นค่าผลรวมแบบ 16-bits ของข้อมูลที่เป็น header และ data ของโปรโตคอล ICMP ข้อมูลที่นำมาคำนวณจะเริ่มจาก address แรกของ header (0x22) ไปจนถึง address สุดท้ายของข้อมูล (ในรูปตัวอย่างคือ 0x49) และก่อนที่จะคำนวณค่า checksum ในช่อง checksum จะต้องเป็น 0 ก่อนเสมอ

รูปตัวอย่างของ ICMP checksum
ค่า checksum ของโปรโตคอล TCP เป็นค่าผลรวมแบบ 16-bits ของข้อมูลที่เป็น header และ data ของโปรโตคอล TCP ข้อมูลที่นำมาคำนวณจะเริ่มจาก address แรกของ Source IP address (อยู่ใน IP Header ) ไปจนถึง address สุดท้ายของข้อมูล (TCP data) โดยค่าที่นำมาคำนวณรวมกับ Header, data ของ TCP ก็จะมีดังรูป
ซึ่งค่า Protocol กับความยาวของ TCP นี้จะนำมาบวกกันแล้วส่งให้ฟังก์ชั่นผ่านตัวแปล DWORD sum ตัวอย่าง IP_PROTO_TCP_V + sizeof(TCP_HEADER) + dlength ในที่นี้ ค่า Protocol ก็คือ IP_PROTO_TCP_V (อยู่ใน ip.h) ค่าความยาวของ TCP ก็คือ sizeof(TCP_HEADER) + dlength (dlength คือความยาวของ TCP data) และก่อนคำนวณค่า checksum ทุกครั้ง ในช่อง TCP checksum จะต้องเป็น 0 เสมอ

รูปตัวอย่างของ TCP checksum
ค่า checksum ของโปรโตคอล UDP เป็นค่า 16-bits ที่ได้จากการบวกแบบสิบหกบิทของข้อมูลแล้วนำมาทำ 1's complement โดยเริ่มจากตำแหน่ง Source IP address ใน IP Header ไปจนถึง Address สุดท้ายของ UDP data โดยที่ก่อนที่จะคำนวณค่า checksum จะต้องทำให้ค่า checksum เก่าเป็นศูนย์ก่อน และค่าที่นำมาคำนวณค่า checksum ด้วยก็คือ Protocol, Total length โดยค่าทั้งสองจะเอามาบวกกันแล้วส่งค่านี้ไปให้ฟังก์ชั่นผ่านตัวแปล DWORD sum
ตัวอย่างค่า UDP checksum
|
|