Thông báo

Collapse
No announcement yet.

Giao thức TCP/IP và Web server với AVR

Collapse
This is a sticky topic.
X
X
 
  • Lọc
  • Giờ
  • Show
Clear All
new posts

  • #61
    Em cũng đang tự viết dựa vào datasheet enc28j60 để viết mấy hàm cơ bản.Thầy có thể giải thích giÙm em cách điều khiển enc28j60 để truyền và nhận gói tin.Sử dụng các thanh ghi để điều khiển,chú thích các thanh ghi và bit của nó.Em đọc datasheet nhưng chưa hiểu.Em cảm ơn thầy.
    , , ,

    Comment


    • #62
      Bây giờ là phần code cho TCP :
      Ta lại tạo 2 file source và header :

      “tcp.c” :
      Code:
      //----------------------------------------------------------------------------
      // Writen by NTTam - PTITHCM
      //----------------------------------------------------------------------------
      #include "packet.h"
      #include "ethernet.h"
      #include "ip.h"
      #include "uart.h"
      #include "tcp.h"
      “tcp.h” :
      Code:
      //----------------------------------------------------------------------------
      // Writen by NTTam - PTITHCM
      //----------------------------------------------------------------------------
      #ifndef TCP_H
      #define TCP_H
      
      #endif //TCP_H
      Đầu tiên là mở file “packet.h”, thêm mô tả TCP header vào :
      Code:
      //--------------------------------------------------------------------------------------
      //Cau truc TCP header
      struct ntTCPHeader
      {
      	unsigned int	srcPort;
      	unsigned int	desPort;
      	unsigned long	seqNumber;
      	unsigned long	ackNumber;
      	unsigned char	Offset;
      	unsigned char	Flags;
      	unsigned int	Window;
      	unsigned int	Checksum;
      	unsigned int	UrgentPtr;
      	unsigned char	optdata[8];
      };
      #define TCP_HEADER_LEN	20
      Định nghĩa các cờ (flags) trong header TCP: vì khi truy xuất buffer, ta chỉ truy xuất được từng byte, sau đó ta dựa vào mask của các cờ được định nghĩa ở đây để truy xuất tới cờ tương ứng.
      Code:
      #define TCP_NON_FLAG (0)
      #define TCP_FIN_FLAG (1<<0)
      #define TCP_SYN_FLAG (1<<1)
      #define TCP_RST_FLAG (1<<2)
      #define TCP_PSH_FLAG (1<<3)
      #define TCP_ACK_FLAG (1<<4)
      #define TCP_URG_FLAG (1<<5)
      #define TCP_ECE_FLAG (1<<6)
      #define TCP_CWR_FLAG (1<<7)
      Tiếp theo ta quay lại “tcp.h”, định nghĩa một số hằng sẽ sử dụng cho giao thức TCP
      Đầu tiên là giá trị MSS (Max Segment Size – Kích thước đoạn dữ liệu tối đa mà ta có thể nhận). Chỗ này các bạn xem lại minh họa chỗ 2 cô thư ký là hiểu ý nghĩa giá trị này liền.
      Code:
      #define MAX_SEGMENT_SIZE	(ETHERNET_BUFFER_SIZE - ETH_HEADER_LEN - IP_HEADER_LEN - TCP_HEADER_LEN)
      Tiếp theo là định nghĩa các trạng thái trong TCP (xem lại phần lưu đồ chuyển đổi trạng thái nhé).
      Code:
      //List the TCP session state
      #define TCP_STATE_CLOSED       0
      #define TCP_STATE_SYN_SENT     1
      #define TCP_STATE_LISTEN       2
      #define TCP_STATE_SYN_RECEIVED 3
      #define TCP_STATE_ESTABLISHED  4
      #define TCP_STATE_FIN_WAIT1    5
      #define TCP_STATE_FIN_WAIT2    6
      #define TCP_STATE_CLOSING      7
      #define TCP_STATE_TIMED_WAIT   8
      #define TCP_STATE_CLOSE_WAIT   9
      #define TCP_STATE_LAST_ACK    10
      Định nghĩa thời gian timeout cho 1 kết nối TCP: cái này rất quan trọng, có thể trong 1 phiên TCP đang kết nối, chưa đến giai đoạn giải tỏa, nhưng phía bên kia vì lý do nào đó mà ngừng liên lạc, nếu chờ hết Timeout ta phải giải tỏa kết nối đó để giải phóng bộ nhớ.
      Code:
      //60 seconds timeout:
      #define TCP_TIMEOUT 60
      Số kết nối đồng thời tối đa cho phép:
      Code:
      //maximum connection count
      #define TCP_MAX_SESSION 8
      Tiếp theo ta khai báo 1 kiểu struct để lưu thông tin về 1 kết nối:
      Code:
      //--------------------------------------------------------------------------------------
      struct tcpSession{
      	unsigned int  desPort;		//Port on the remote host
      	unsigned int  srcPort;		//Port on the local host
      	unsigned long desIP;		//IP address of the remote host
      	unsigned long seqNumber;	//Sequence number
      	unsigned long ackNumber;	//Acknowlegement number
      	unsigned char sesState;	//Current state of TCP session
      	unsigned int  srcWin;		
      	unsigned int  desWin;		
      	unsigned long lastRxAck;	//Last Received Ack
      	unsigned char nextAck;
      	unsigned char timeOut;	//Session time out
      	void(*appDataIn)(unsigned char* dataBuffer,unsigned int dataLen,struct tcpSession *pSession);
      	unsigned char appID; 		//Upper layer application ID 
      	unsigned char appState; 	//Upper layer application state
      };
      Bây giờ chuyển sang “tcp.c”:
      Khai báo 1 bảng TCP session, trong đó mỗi dòng là 1 struct tcpSession lưu thông tin về 1 kết nối:
      Code:
      //--------------------------------------------------------------------------------------
      struct tcpSession tcpSessionTable[TCP_MAX_SESSION];
      Viết hàm khởi tạo số tuần tự (sequence number) cho 1 kết nối TCP. Các bạn xem lại phần minh họa (2 cô thư ký). Mỗi phía sẽ tự chọn 1 số tuần tự để bắt đầu. Trên máy tính, con số này thường được lấy theo thời gian. Ở đây cho đơn giản, ta chỉ chọn đại 1 số mà thôi.
      Code:
      //--------------------------------------------------------------------------------------
      //Ham khoi tao so tuan tu cho mot phien TCP
      // Hien tai su dung gia tri 1234 (may tinh thuong dung gia tri thoi gian hien tai)
      unsigned long TCPInitSequenceNumber()
      {
      	return(1234);
      }
      Tiếp theo là hàm đóng 1 phiên TCP:
      Code:
      //--------------------------------------------------------------------------------------
      //Ham dong mot phien TCP
      void TCPCloseSession(unsigned char socketnum)
      {
      	tcpSessionTable[socketnum].sesState = TCP_STATE_CLOSED;
      	#ifdef TCP_DEBUG
      	printf("Close TCP session %d\r\n",socketnum);
      	#endif
      }
      Viết hàm khởi tạo các biến cho giao thức TCP:
      Code:
      //--------------------------------------------------------------------------------------
      //Khoi dong cac gia tri trong bang TCP session
      void TCPInit()
      {
      	unsigned char i = 0;
      	for(i=0; i<TCP_MAX_SESSION; i++){
      		TCPCloseSession(i);
      	}
      }
      Code:
      Hàm tìm kiếm 1 phiên TCP đang rỗi trong bảng TCP session table (để mở kết nối mới)
      //--------------------------------------------------------------------------------------
      //Tim mot session TCP dang roi
      unsigned char TCPGetFreeSession(){
      	unsigned char i;
      	for(i=0; i<TCP_MAX_SESSION; i++){
      		if (tcpSessionTable[i].sesState == TCP_STATE_CLOSED)
      			return i;
      	}
      	//no free closed socket fount! -> kick an TIMED_WAIT socket
      	for(i=0; i<TCP_MAX_SESSION; i++){
      		if (tcpSessionTable[i].sesState == TCP_STATE_TIMED_WAIT){
      			TCPCloseSession(i);
      			return i;
      		}
      	}
      	//no more free sockets ... return invalid val	
      	return(TCP_MAX_SESSION);
      }
      Viết hàm khởi tạo một kết nối mới (ở chế độ server):
      Code:
      //--------------------------------------------------------------------------------------
      //Ham khoi tao mot session TCP o che do server de cho ket noi
      void	TCPCreateSession(unsigned int  sourcePort, prog_void* appService)
      {
      	unsigned char i;
      	i = TCPGetFreeSession();
      	if(i >= TCP_MAX_SESSION)
      		i = 0;	//force session 0
      	tcpSessionTable[i].srcPort = sourcePort;
      	tcpSessionTable[i].sesState = TCP_STATE_LISTEN;		//Current state of TCP session
      	tcpSessionTable[i].srcWin = 8192;//NETSTACK_BUFFERSIZE - ETH_HEADER_LEN - IP_HEADER_LEN - TCP_HEADER_LEN - 16;
      	tcpSessionTable[i].desWin = tcpSessionTable[i].srcWin;
      	tcpSessionTable[i].timeOut = TCP_TIMEOUT;		//Session time out
      	tcpSessionTable[i].appDataIn = appService;
      	#ifdef TCP_DEBUG
      	printf("TCP session created: %d\r\n", i);
      	#endif
      
      }
      Hàm kiểm tra Timeout của các phiên TCP đang kết nối
      Code:
      //--------------------------------------------------------------------------------------
      //Duoc goi moi giay de kiem tra Time out cho cac phien TCP,
      // giai phong cac phine TCP bi treo
      void TCPCheckTimeOut(){
      	unsigned char i;
      	for(i=0; i<TCP_MAX_SESSION; i++){
      		//decrement ttl:
      		if ((tcpSessionTable[i].sesState != TCP_STATE_CLOSED) && (tcpSessionTable[i].sesState != TCP_STATE_LISTEN)){
      			if(tcpSessionTable[i].timeOut)
      				tcpSessionTable[i].timeOut--;
      			
      			//if socket TTL count is zero, close this socket!
      			if (tcpSessionTable[i].timeOut == 0){
      				TCPCloseSession(i);
      			}
      		}
      	}
      }
      Hàm tính checksum cho gói TCP
      Code:
      //--------------------------------------------------------------------------------------
      //Tinh checksum cho goi TCP
      unsigned int checksum(unsigned char *buffer, unsigned int len, unsigned long csum32)
      {
      	unsigned int  res16 = 0x0000;
      	unsigned char data_hi;
      	unsigned char data_lo;
      	while(len > 1){
      		data_hi = *buffer++;
      		data_lo = *buffer++;
      		res16 = (((unsigned int)data_hi << 8) + data_lo);
      		csum32 = csum32 + res16;
      		len -=2;
      	}
      	if(len > 0){
      		data_hi = *buffer;
      		res16   = (unsigned int)data_hi<<8;
      		csum32 = csum32 + res16;
      	}
      	while(csum32>>16)
      		csum32 = (csum32 & 0xFFFF)+ (csum32 >> 16);
      	//csum32 = ((csum32 & 0x0000FFFF)+ ((csum32 & 0xFFFF0000) >> 16));	
      	res16  =~(csum32 & 0x0000FFFF);
      	return (res16);
      }
      Tiếp theo là hai hàm chính của giao thức:

      Hàm gửi 1 đoạn dữ liệu đi bằng giao thức TCP:
      Code:
      //--------------------------------------------------------------------------------------
      //Gui di mot goi TCP
      void TCPPackedSend(struct tcpSession *pSession, unsigned char Flags, unsigned int len, unsigned char *dataBuffer)
      {
      	unsigned int tmp;
      	unsigned long checksum32;
      	//Make pointer to TCP header
      	struct ntTCPHeader* tcpHeader;
      	struct ntIPHeader* ipHeader;
      	//Neu dang syn thi them option ve MSS
      	if(Flags & TCP_SYN_FLAG){
      		//Option data
      		dataBuffer[0] = 0x02;
      		dataBuffer[1] = 0x04;
      		dataBuffer[2] = (MAX_SEGMENT_SIZE >> 8) & 0xff;
      		dataBuffer[3] = MAX_SEGMENT_SIZE & 0xff;
      		dataBuffer[4] = 0x01;
      		dataBuffer[5] = 0x03;
      		dataBuffer[6] = 0x03;
      		dataBuffer[7] = 0x00;
      		//Move data pointer to make room for TCP header
      	}
      	dataBuffer -= TCP_HEADER_LEN;
      	tcpHeader = (struct ntTCPHeader*)dataBuffer;
      	//Fill UDP header
      	tcpHeader->srcPort = HTONS(pSession->srcPort);
      	tcpHeader->desPort = HTONS(pSession->desPort);
      	tcpHeader->seqNumber = HTONL(pSession->seqNumber);
      	pSession->seqNumber = pSession->seqNumber + len;
      	if(Flags & (TCP_FIN_FLAG|TCP_SYN_FLAG))
      		(pSession->seqNumber)++;
      	tcpHeader->ackNumber = HTONL(pSession->ackNumber);
      	if(Flags & TCP_SYN_FLAG){
      		tcpHeader->Offset = (0x07<<4);
      		len += (TCP_HEADER_LEN + 8);
      	}else{
      		tcpHeader->Offset = (0x05<<4);
      		len += TCP_HEADER_LEN;
      	}
      	tcpHeader->Flags = Flags;
      	tcpHeader->Window = HTONS(pSession->srcWin);//((NETSTACK_BUFFERSIZE-20-14));
      	tcpHeader->Checksum = 0;
      	tcpHeader->UrgentPtr = 0x0000;
      	//Generate checksum
      	ipHeader = (struct ntIPHeader*)(dataBuffer-IP_HEADER_LEN);
      	ipHeader->srcIPAddr = HTONL(ipGetConfig()->ip);
      	ipHeader->desIPAddr = HTONL(pSession->desIP);
      	ipHeader->Checksum = HTONS(len);
      	ipHeader->TTL = 0x00;
      	ipHeader->Protocol = IP_PROTO_TCP;
      	checksum32 = 0;
      	tmp = len + 12;
      	tmp = checksum (((unsigned char *)ipHeader+8), tmp, checksum32);
      	tcpHeader->Checksum = HTONS(tmp);
      	ipSend(pSession->desIP, IP_PROTO_TCP, len, (unsigned char *)tcpHeader);	
      }
      Hàm xử lý khi nhận được 1 gói TCP
      Code:
      //--------------------------------------------------------------------------------------
      //Ham xu ly goi TCP nhan duoc, duoc goi boi giao thuc IP (IPProcess)
      void TCPProcess(unsigned char *buffer, unsigned int len)
      //Ham xu ly cho giao thuc TCP
      // Duoc thuc thi khi nhan duoc mot goi TCP (goi boi netstackIPProcess)
      // buffer: co tro den dau goi IP (bat dau IP Header)
      // len   : chieu dai buffer
      {
      	unsigned char i,ipHeaderLen,tcpHeaderLen;
      	unsigned int dataLen;
      	unsigned long tmp;
      	struct ntIPHeader* ipHeader;
      	struct ntTCPHeader* tcpHeader;
      	unsigned char *tcpData;
      	//Khoi tao cac co tro den Header IP va TCP
      	ipHeader = (struct ntIPHeader*)(buffer);
      	ipHeaderLen = ((ipHeader->verHdrLen) & 0x0F) << 2;
      	//
      	tcpHeader = (struct ntTCPHeader*)(buffer+ipHeaderLen);
      	tcpHeaderLen = ((tcpHeader->Offset) & 0xF0) >> 2;
      	//
      	tcpData = (buffer+ipHeaderLen+tcpHeaderLen);
      	dataLen = HTONS(ipHeader->Len) - (ipHeaderLen + tcpHeaderLen);
      	//Tim kiem mot phien TCP co san cho goi nay
      	for(i = 0; i < TCP_MAX_SESSION; i++){	//Check session table
      		if(tcpSessionTable[i].sesState != TCP_STATE_CLOSED){		//If not closed session
      			if(tcpSessionTable[i].srcPort == HTONS((tcpHeader->desPort))){	//If matched local port
      				if(tcpSessionTable[i].desPort == HTONS((tcpHeader->srcPort))&&(tcpSessionTable[i].desIP == HTONL((ipHeader->srcIPAddr)))){
      					break;	//Thoat khoi vong lap for, luc nay gia tri cua i chinh la chi so cua phien TCP tuong ung
      				}
      			}
      		}
      	}
      	if(i == TCP_MAX_SESSION){	//Neu khong co 1 phien TCP dang ton tai cho goi nay
      		//Tim 1 phien dang o trang thai LISTEN (doi ket noi) cho local port nay
      		for(i=0; i < TCP_MAX_SESSION; i++){
      			if(tcpSessionTable[i].sesState == TCP_STATE_LISTEN){
      				if(tcpSessionTable[i].srcPort == HTONS((tcpHeader->desPort))){	//If matched local port
      					//Cap nhat remote port va remote IP
      					tcpSessionTable[i].desPort = HTONS((tcpHeader->srcPort));
      					tcpSessionTable[i].desIP = HTONL((ipHeader->srcIPAddr));
      					//Dong thoi tao ra 1 session moi de cho ket noi khac den local port nay
      					TCPCreateSession(tcpSessionTable[i].srcPort,tcpSessionTable[i].appDataIn);
      					break;
      				}
      			}
      		}
      	}
      	if(i == TCP_MAX_SESSION){
      		#ifdef TCP_DEBUG
      		printf("No TCP session found\r\n");
      		#endif
      		return;	//Neu khong co phien TCP nao danh cho goi nay thi thoat ra
      	}
      	#ifdef TCP_DEBUG
      	printf("TCP session found: %d\r\n",i);
      	#endif
      	//Bat dau xu ly giao thuc
      	tcpSessionTable[i].timeOut = TCP_TIMEOUT;	//Reset lai gia tri Time out
      	//Truong hop nhan duoc yeu cau reset lai ket noi
      	if ((tcpHeader->Flags) & TCP_RST_FLAG){
      		//Chap nhan dong ket noi
      		TCPCloseSession(i);
      		return;
      	}
      	//Kiem tra trang thai hien tai cua phien TCP
      	switch (tcpSessionTable[i].sesState){
      		//Neu la trang thai doi ket noi: TCP_STATE_LISTEN
      		case(TCP_STATE_LISTEN):
      			//Chi xu ly neu co SYN duoc set (yeu cau thiet lap ket noi)
      			if ((tcpHeader->Flags) == TCP_SYN_FLAG){
      				//Chuyen sang trang thai ke tiep la TCP_STATE_SYN_RECEIVED
      				tcpSessionTable[i].sesState = TCP_STATE_SYN_RECEIVED;
      				//Khoi tao gia tri sequence
      				tcpSessionTable[i].seqNumber = HTONL(TCPInitSequenceNumber());
      				//Ack chinh la so tuan tu nhan duoc cong 1
      				tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+1;
      				tcpSessionTable[i].desWin = HTONS((tcpHeader->Window));
      				//Goi tra xac nhan va co SYN (SYN & ACK)
      				TCPPackedSend(&tcpSessionTable[i],(TCP_SYN_FLAG|TCP_ACK_FLAG),0,tcpData);
      				//Tang so tuan tu len 1
      				//tcpSessionTable[i].seqNumber++;
      				#ifdef TCP_DEBUG
      				printf("SYN received\r\n");
      				#endif
      			}
      			break;
      		//Neu la trang thai TCP_STATE_SYN_RECEIVED
      		case(TCP_STATE_SYN_RECEIVED):
      			//Neu co co ACK (cho ban tin SYN & ACK truoc do)
      			if ((tcpHeader->Flags) == TCP_ACK_FLAG){
      				//Kiem tra ack trong goi tin den, neu dung thi thiet lap ket noi hoan tat
      				if((tcpSessionTable[i].seqNumber) == HTONL((tcpHeader->ackNumber))){
      					tcpSessionTable[i].sesState = TCP_STATE_ESTABLISHED;
      					//Goi tiep theo gui di se co co ACK
      					tcpSessionTable[i].nextAck = 1;
      					#ifdef TCP_DEBUG
      					printf("Connection established\r\n");
      					#endif
      				}
      			}else{	//Neu khong dung ACK
      				//Khong lam gi ca, goi tin do khong hop le
      				//TCPCloseSession(i);
      			}
      			break;
      		//Truong hop ket noi da duoc thiet lap
      		case(TCP_STATE_ESTABLISHED):
      			//Neu nhan duoc yeu cau ket thuc ket noi tu client
      			if ((tcpHeader->Flags) & TCP_FIN_FLAG){
      				//Chuyen sang trang thai ke tiep la trang thai cho ACK cuoi
      				//Dung ra o day phai chuyen sang trang thai TCP_STATE_CLOSE_WAIT nhung khong can thiet
      				//  vi o day ta co the dong ket noi ngay ma khong can cho gui xong du lieu
      				tcpSessionTable[i].sesState = TCP_STATE_LAST_ACK;
      				//Cap nhat ack
      				tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber)) + dataLen;
      				tcpSessionTable[i].ackNumber++;	//Tang 1 cho co FIN
      				//Gui xac nhan ACK cho yeu cau dong ket noi dong thoi thong bao san sang dong ket noi
      				TCPPackedSend(&tcpSessionTable[i],TCP_ACK_FLAG,0,tcpData);
      				TCPPackedSend(&tcpSessionTable[i],(TCP_FIN_FLAG|TCP_ACK_FLAG),0,tcpData);
      				//Dang le truyen o trang thai CLOSE_WAIT nhung ta thuc hien o day luon
      				TCPCloseSession(i);
      			//Neu khong (dang truyen du lieu)
      			}else{
      				//Kiem tra ACK tu remote host
      				if((tcpHeader->Flags) & TCP_ACK_FLAG){	//Neu co co ACK thi kiem tra gia tri ACK
      					tcpSessionTable[i].lastRxAck = HTONL((tcpHeader->ackNumber));
      					if ((tcpSessionTable[i].seqNumber) == HTONL((tcpHeader->ackNumber))){	//Dung ACK
      						#ifdef TCP_DEBUG
      						printf("Got ACK\r\n");
      						#endif
      					}else{	//Phia ben kia khong nhan duoc du thong tin
      						//Sua loi o day
      						//Process error correction here
      						//Not finish yet, temporary just ignore it and continue with next data
      						//Chua thuc hien
      						tcpSessionTable[i].seqNumber = HTONL((tcpHeader->ackNumber));
      						#ifdef TCP_DEBUG
      						printf("Miss ACK:got %d\r\nExpected:%d\n\r",HTONL((tcpHeader->ackNumber)),tcpSessionTable[i].seqNumber+1);										
      						#endif
      					}
      				}
      				//--Ket thuc kiem tra ACK
      				//Kiem tra sequence number
      				tmp = HTONL((tcpHeader->seqNumber));
      				//Neu khong dung goi dang cho nhan
      				if (tmp != tcpSessionTable[i].ackNumber){
      					//there was an error, check what to do next:
      					#ifdef TCP_DEBUG
      					printf("Incorrect seq, got:%d,expexted:%d\r\n",tmp,tcpSessionTable[i].ackNumber);
      					#endif
      					if (tmp < tcpSessionTable[i].ackNumber){
      						//Neu dang doi du lieu bat dau tu byte thu n nhung ta nhan duoc doan du lieu bat dau tu (n-k)
      						//Tinh phan du lieu thua (k = n - (n-k))
      						tmp = (tcpSessionTable[i].ackNumber - tmp);
      						//Neu doan du lieu thua it hon du lieu nhan duoc
      						if(tmp < dataLen){
      							//Bo di phan du lieu thua, nhan phan con lai
      							tcpData += tmp;
      							dataLen = dataLen - tmp;
      						}else{	//Neu tat ca du lieu nhan duoc deu thua
      							//Gui lai ACK, bo goi vua nhan duoc
      							dataLen = 0;
      							TCPPackedSend(&tcpSessionTable[i],(TCP_ACK_FLAG),0,tcpData);
      							return;
      						}
      					//Neu seq > ack (tuc la co 1 doan du lieu bi mat)
      					}else{ //tmp > tcp....
      						//Yeu cau gui lai
      						TCPPackedSend(&tcpSessionTable[i],(TCP_ACK_FLAG),0,tcpData);
      						return;
      					}
      				}
      				//Neu thuc thi den day nghia la sequence number == ack number (chinh xac)
      				//--Ket thuc kiem tra so tuan tu
      				//Kiem tra chieu dai buffer de chac chan la chieu dai du lieu nhan duoc khong qua buffer
      				//
      				if (tcpData > (buffer + ETHERNET_BUFFER_SIZE))
      					tcpData = (buffer + ETHERNET_BUFFER_SIZE);
      				if ((tcpData + dataLen) > buffer + ETHERNET_BUFFER_SIZE){
      					dataLen = (buffer + ETHERNET_BUFFER_SIZE) - tcpData;				
      				}
      				//
      				//Cap nhat ack cho lan nhan ke tiep
      				tcpSessionTable[i].ackNumber = tcpSessionTable[i].ackNumber + dataLen;
      				#ifdef TCP_DEBUG
      				printf("Data length (%d), buffer size(%d)\n\r",dataLen,(buffer + ETHERNET_BUFFER_SIZE - tcpData));
      				printf("Ack Number (%d)\n\r",tcpSessionTable[i].ackNumber);
      				#endif
      				//Goi tiep theo gui di se co co ACK
      				tcpSessionTable[i].nextAck = 1;
      				//Goi ham xu ly lop ung dung
      				if(dataLen != 0){
      					(tcpSessionTable[i].appDataIn)(tcpData, dataLen,&tcpSessionTable[i]);
      				}
      			}
      			//--Ket thuc xu ly truong hop dang truyen du lieu
      			break;
      		//Neu la trang thai doi LAST_ACK (2 phia deu san sang dong ket noi, dang doi xac nhan ack cuoi cung)
      		case(TCP_STATE_LAST_ACK):
      			//socket is closed
      			tmp = HTONL((tcpHeader->seqNumber));
      			//Kiem tra ACK, neu dung ACK
      			if (tmp == tcpSessionTable[i].seqNumber + 1){
      				TCPCloseSession(i);
      			}else{
      				//Gui lai co FIN & ACK
      				TCPPackedSend(&tcpSessionTable[i], (TCP_FIN_FLAG|TCP_ACK_FLAG), 0, tcpData);
      			}
      			break;
      
      		//Truong hop ngat ket noi thu dong, da nhan co FIN tu remote host va xac nhan
      		case(TCP_STATE_CLOSE_WAIT):
      			//Truong hop nay se khong xay ra vi o tren ta chuyen truc tiep
      			//  sang LAST_ACK khi nhan duoc yeu cau dong ket noi
      			tcpSessionTable[i].sesState = TCP_STATE_LAST_ACK;
      			if(dataLen){
      				tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber)) + dataLen;
      			}else{	//Neu dataLen == 0 thi cung tang so tuan tu len 1
      				tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+1;
      			}
      			//tcpSessionTable[i].seqNumber = HTONL((tcpHeader->ackNumber));
      			TCPPackedSend(&tcpSessionTable[i], (TCP_FIN_FLAG|TCP_ACK_FLAG), 0, tcpData);
      			break;
      		//Truong hop dang o trang thai FIN WAIT 1 (da truyen du lieu xong,
      		//  san sang dong ket noi va da gui di co FIN va dang cho ACK)
      		case(TCP_STATE_FIN_WAIT1):
      			//if we receive FIN
      			tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+1;
      			if (tcpHeader->Flags == TCP_FIN_FLAG){	//Neu chi nhan duoc co FIN
      				//Chuyen sang trang thai CLOSING va gui ACK
      				tcpSessionTable[i].sesState = TCP_STATE_CLOSING;
      				TCPPackedSend(&tcpSessionTable[i], (TCP_ACK_FLAG), 0, tcpData);
      				//tcpSessionTable[i].seqNumber++;
      				#ifdef TCP_DEBUG
      				printf("Closing\n\r");
      				#endif
      			}else if(tcpHeader->Flags == (TCP_FIN_FLAG | TCP_ACK_FLAG)){	//Neu nhan dong thoi FIN va ACK
      				//Chuyen sang trang thai TIME_WAIT va gui ACK
      				//  nhung o day do chua co timer nen ta chuyen luon sang dong ket noi
      				if (HTONL((tcpHeader->ackNumber)) == tcpSessionTable[i].seqNumber){
      					//TCPPackedSend(&tcpSessionTable[i], (TCP_ACK_FLAG), 0, tcpData);
      					TCPCloseSession(i);
      					#ifdef TCP_DEBUG
      					printf("End\n\r");
      					#endif
      				}else{	//Neu khong dung ack cho thong bao FIN
      					//Chuyen sang cho co ACK cuoi cung
      					tcpSessionTable[i].sesState = TCP_STATE_LAST_ACK;
      					#ifdef TCP_DEBUG
      					printf("Last ack\n\r");
      					#endif
      				}
      				//Gui xac nhan cho co FIN
      				TCPPackedSend(&tcpSessionTable[i], (TCP_ACK_FLAG), 0, tcpData);
      				//tcpSessionTable[i].seqNumber++;
      			}else if(tcpHeader->Flags == TCP_ACK_FLAG){	//Neu chi nhan duoc ACK
      				//Chuyen sang trang thai FIN WAIT2
      				tcpSessionTable[i].sesState = TCP_STATE_FIN_WAIT2;
      				#ifdef TCP_DEBUG
      				printf("Fin wait 2\n\r");
      				#endif
      			}
      			break;
      		//Neu dang o trang thai FIN WAIT 2 (san sang dong ket noi va gui co FIN,
      		//  phia ben kia da xac nhan nhung van chua san sang dong ket noi
      		case(TCP_STATE_FIN_WAIT2):
      			//Neu nhan duoc co FIN
      			if (tcpHeader->Flags & TCP_FIN_FLAG){
      				if(dataLen){
      					tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+dataLen;
      				}else{
      					tcpSessionTable[i].ackNumber = HTONL((tcpHeader->seqNumber))+1;
      				}
      				//FIN -> goto TIMED WAIT
      				tcpSessionTable[i].sesState = TCP_STATE_TIMED_WAIT;
      				TCPPackedSend(&tcpSessionTable[i], (TCP_ACK_FLAG), 0, tcpData);
      				//Chua co timer thi dong ket noi o day luon
      				TCPCloseSession(i);
      				#ifdef TCP_DEBUG
      				printf("End\n\r");
      				#endif
      			}
      			break;
      		case(TCP_STATE_TIMED_WAIT):
      			break;
      		case(TCP_STATE_CLOSING):
      			tcpSessionTable[i].sesState = TCP_STATE_TIMED_WAIT;
      			break;
      		default:
      			TCPCloseSession(i);
      	}
      	//we must set timed wait TTL here because timed wait is not packet triggered
      	if (tcpSessionTable[i].sesState == TCP_STATE_TIMED_WAIT){
      		tcpSessionTable[i].timeOut = 5; //5 seconds timeout
      	}
      	return;
      }
      //--------------------------------------------------------------------------------------
      Hai hàm này khiếp quá, nhìn vô thấy oải rồi, từ từ giải thích, không hiểu sao hồi xưa mình lại viết phức tạp như vậy.
      Hay là mọi người cứ từ từ nghiên cứu, chỗ nào không hiểu thì cứ hỏi . Giờ nghĩ tới viết giải thích cho code thấy nản quá. Viết giải thích cho code có khi còn khó hơn viết code .
      Last edited by nttam79; 10-11-2011, 11:55.

      Comment


      • #63
        Giao thức UDP:
        Tiếp theo, ta chuyển sang giao thức UDP, trong 3 giao thức ở lớp này (TCP, UDP và ICMP) thì UDP là giao thức đơn giản nhất, dễ viết nhất.
        Trong chồng giao thức IP, nhiệm vụ của UDP là khi nhận 1 segment dữ liệu từ ứng dụng gửi xuống, nó sẽ gửi đi ngay đến địa chỉ IP và port được yêu cầu mà không cần đánh số thứ tự, bắt tay thiết lập kết nối hay thậm chí không quan tâm đến việc dữ liệu đó có đến được đích hay không.
        Header của giao thức UDP rất đon giản: chỉ gồm có 4 trường: port nguồn, port đích, chiều dài gói tin và checksum.


        Trong thực tế, UDP được sử dụng để gửi đi các dữ liệu mà yêu cầu về độ trễ nhỏ quan trọng hơn yêu cầu về độ tin cậy. Ví dụ như dữ liệu của các video stream, audio stream, các báo hiệu nhanh, hay đơn giản là tương tác trong các game online.

        Vậy ta mở file “packet.h” thêm khai báo header UDP vào:
        Code:
        //--------------------------------------------------------------------------------------
        //Cau truc UDP header
        struct ntUDPHeader
        {
        	unsigned int	srcPort;
        	unsigned int	desPort;
        	unsigned int	Len;
        	unsigned int	Checksum;
        };
        #define UDP_HEADER_LEN	8
        Sau đó tạo file source và header tương ứng:
        “udp.c”
        Code:
        //----------------------------------------------------------------------------
        // Writen by NTTam - PTITHCM
        //----------------------------------------------------------------------------
        #include "packet.h"
        #include "ip.h"
        #include "uart.h"
        “udp.h”
        Code:
        //----------------------------------------------------------------------------
        // Writen by NTTam - PTITHCM
        //----------------------------------------------------------------------------
        #ifndef		UDP_H
        #define 	UDP_H
        //----------------------------------------------------------------------------
        
        #endif 		//UDP_H
        Ta chỉ viết 2 hàm cho giao thức UDP:
        Hàm gửi gói tin bằng UDP:
        Code:
        //----------------------------------------------------------------------------
        //Ham gui di mot goi UDP
        void udpSend(unsigned long dstIp, unsigned int dstPort, unsigned int len, unsigned char* udpData)
        {
        	struct ntUDPHeader* udpHeader;
        	udpHeader = (struct ntUDPHeader*)(udpData - UDP_HEADER_LEN);
        	len += UDP_HEADER_LEN;
        	udpHeader->desPort = HTONS(dstPort);
        	udpHeader->srcPort  = HTONS(dstPort);
        	udpHeader->Len = HTONS(len);
        	udpHeader->Checksum = 0;
        	ipSend(dstIp, IP_PROTO_UDP, len, (unsigned char*)udpHeader);
        }
        Hàm xử lý gói tin nhận được:
        Code:
        //--------------------------------------------------------------------------------------
        //Ham xu ly goi UDP nhan duoc, duoc goi boi ham xu ly goi IP (IPProcess)
        // Hien chua co ung dung chay UDP nen ham nay trong
        void UDPProcess(unsigned int len, struct ntIPHeader* packet)
        {
        	dhcpIn((len - IP_HEADER_LEN - UDP_HEADER_LEN), (struct netDhcpHeader*)((char*)packet - IP_HEADER_LEN - UDP_HEADER_LEN));
        	#ifdef NET_DEBUG
        	printf("NetStack UDP/IP Rx Dummy Handler\r\n");
        	#endif
        }
        Vì trong project này, chúng ta chỉ sử dụng UDP cho 1 ứng dụng duy nhất là DHCP nên ở đây ta chỉ gọi hàm dhcpIn để xử lý. Hàm này ta vẫn chưa viết nhé. Nếu ta còn dùng UDP cho các giao thức khác thì phức tạp hơn 1 tý, tuy nhiên vẫn đơn giản hơn nhiều so với TCP.
        Tiếp theo sẽ là DHCP và HTTP, xong cái này là các bạn có thể truy cập web trên mạch được rồi (nếu có mạch ).

        Comment


        • #64
          Đã built xong code đến phần Ping được. Trong quá trình làm theo anh Tâm có vài điểm anh Tâm nói chưa rõ lắm nên hôm nay Huy port lên phần code mới làm xong và biên dịch OK.
          Anh Tâm có nhầm một chỗ như sau :
          Trong hàm này ta có sử dụng định nghĩa vector ngắt (ISR), do đó ta cần include file tương ứng vào. Thêm dòng này vào đầu file "ehternet.c"
          Code:
          #include <avr/interrupt.h>
          Trong hàm này, ta sử dụng 2 biến toàn cục là eth_got_frame và time_watchdog, hai biến này cần được khai báo trong file “enc28j60.c” (nên để ở dầu file) thay bằng ethernet.c
          Code:
          unsigned char eth_got_frame = 0;
          volatile unsigned int time_watchdog;

          Và ntAVRnet.c cần include như thế này
          <
          #include <avr/io.h>
          #include "ntAVRnet.h"
          #include "ip.h"
          extern struct ipConfig IpMyConfig;
          >
          Có gì sai anh Tâm chỉnh dùm nha. Tối nay về nạp vào mạch rồi Ping thôi. keke
          AVRnet NTT.zip
          Click image for larger version

Name:	Built code .jpg
Views:	1
Size:	81.4 KB
ID:	1353623

          Email:
          Tel: 0983.497.310

          Comment


          • #65
            Nguyên văn bởi tienhuypro Xem bài viết
            Đã built xong code đến phần Ping được. Trong quá trình làm theo anh Tâm có vài điểm anh Tâm nói chưa rõ lắm nên hôm nay Huy port lên phần code mới làm xong và biên dịch OK.
            Anh Tâm có nhầm một chỗ như sau :
            Trong hàm này ta có sử dụng định nghĩa vector ngắt (ISR), do đó ta cần include file tương ứng vào. Thêm dòng này vào đầu file "ehternet.c"
            Code:
            #include <avr/interrupt.h>
            Trong hàm này, ta sử dụng 2 biến toàn cục là eth_got_frame và time_watchdog, hai biến này cần được khai báo trong file “enc28j60.c” (nên để ở dầu file) thay bằng ethernet.c
            Code:
            unsigned char eth_got_frame = 0;
            volatile unsigned int time_watchdog;

            Và ntAVRnet.c cần include như thế này
            <
            #include <avr/io.h>
            #include "ntAVRnet.h"
            #include "ip.h"
            extern struct ipConfig IpMyConfig;
            >
            Có gì sai anh Tâm chỉnh dùm nha. Tối nay về nạp vào mạch rồi Ping thôi. keke
            [ATTACH]35223[/ATTACH]
            [ATTACH=CONFIG]35224[/ATTACH]
            A, đúng rồi đó, bạn tienhuypro đã phát hiện rất chính xác, phải là ethernet.c chứ không phải enc28j60.c
            Cảm ơn tienhuypro nhé.

            Comment


            • #66
              Thầy ơi ,thầy xem lại cái ipchecksum với.Em đọc trong datasheet thì thấy khác.Em dÙng đủ mọi cách viết chương trình trên máy tính với cfree.debug avrstudio,code viết trên codevision.Chạy chả đúng tẹo nào.
              , , ,

              Comment


              • #67
                IP checksum tôi đã giải thích ở post trước rồi mà, chương trình này đã test trên mạch, debug bản tin bằng wireshark và chạy chính xác. Nếu bạn test trên các môi trường khác thì chú ý là trật tự các byte thấp, byte cao trong số 16 bit cũng như trên buffer có thể khác nhau giữa trên máy tính và trên AVR cũng như các VĐK khác. điều này sẽ dẫn đến sai checksum nhé. Bạn có thể cho biết bạn chạy như thế nào để kiểm tra đúng hay sai không?

                Comment


                • #68
                  Em biết avr lưu kiểu big endian.Em cũng hiểu cái giải thuật đó.Cộng giá trị 16bit nếu giá trị cộng trên 16bit thì cộng 1 với 16bit thấp.Cộng đến khi kô còn trên 16bit.Em viết trên cfree thì đúng,trên codevision nó chạy kô đúng,dịch phải 16bit toàn nhận giá trị 0.
                  , , ,

                  Comment


                  • #69
                    Chào các bạn !
                    Code anh Tâm viết rất ổn mình đã test Ping OK rồi nhưng phải sửa lại tí define và code để phù hợp với mạch mình thiết kế. Mình port vài cái hình và code test cho Board bà con xem nhé !
                    Click image for larger version

Name:	IP Laptop.jpg
Views:	1
Size:	64.6 KB
ID:	1353629Click image for larger version

Name:	CMD Ping 192.168.9.51.jpg
Views:	1
Size:	86.9 KB
ID:	1353630Click image for larger version

Name:	Chinh lai define.jpg
Views:	1
Size:	78.0 KB
ID:	1353631Click image for larger version

Name:	AVRnet Ping.jpg
Views:	1
Size:	80.3 KB
ID:	1353632Click image for larger version

Name:	Ping IP laptop AVRnet1.JPG
Views:	1
Size:	119.1 KB
ID:	1353633
                    AH Thanks anh Tâm cái nữa nè !
                    Last edited by tienhuypro; 10-11-2011, 23:37.

                    Email:
                    Tel: 0983.497.310

                    Comment


                    • #70
                      Thêm code vì không cho up >5 file
                      Attached Files
                      Last edited by tienhuypro; 11-11-2011, 00:42.

                      Email:
                      Tel: 0983.497.310

                      Comment


                      • #71
                        Nguyên văn bởi tienhuypro Xem bài viết
                        Chào các bạn !
                        Code anh Tâm viết rất ổn mình đã test Ping OK rồi nhưng phải sửa lại tí define và code để phù hợp với mạch mình thiết kế. Mình port vài cái hình và code test cho Board bà con xem nhé !
                        Mừng quá , vậy là code mình post hướng dẫn không có gì sai. Vẫn biết là chương trình mình viết thì chạy nhưng không biết post lên có sai sót gì không và mọi người có làm theo được không.
                        @Huy: nếu đã ping được thì Webserver, điều khiển qua Internet,... chỉ là chuyện nhỏ, vì như vậy là phần hardware giao tiếp ethernet và giao thức IP đã chạy OK, còn lại sử dụng thế nào là do các bạn thôi.
                        TienHuy đúng là dân pro thiệt đó, mặc dù viết hướng dẫn nhưng mình biết tự buid được mạch và code của mình theo đó cũng là rất khó, hướng dẫn chỉ là chung chung thôi. Huy có thể thay title của file code được rồi đó .

                        Comment


                        • #72
                          Nguyên văn bởi rptdnmqs
                          Nó chạy sai.em tự mò theo datasheet viết code.Rồi đối chiếu với code của thầy Tâm.Dịch xong debug bằng avrstudio chạy sai mất.Nên em chèn asm trong codevision.Nhưng lại chưa rõ cách chèn.Cũng mò tiếp thấy nó dịch vẫn sai nên em cứ loay hoay cái checksum.Chẳng biết sao nữa đành dÙng winavr vậy.Giá mà nó dịch được như thằng CCS thì tốt quá.Ôi 1 chút vấn đề làm mất thời gian.Em xin lỗi vì đã làm phiền.Thanks!.
                          Chuyển code giữa 2 trình biên dịch là 1 công việc mất nhiều thời gian và công sức lắm, không khác gì viết lại hết, đòi hỏi phải biết hết những "lắt léo" trong mỗi trình biên dịch. Lúc trước tôi cũng định chuyển toàn bộ code project này sang codevision, nhưng được có vài module thấy mất thời gian quá nên thôi. Nếu bạn chuyển được sang codevision thì cũng giống như là tự mình viết lại toàn bộ đó. Cố gắng lên, vì theo tôi biết không có code giao thức TCP/IP trên CodevisionAVR, nếu bạn hoàn thành thì sẽ giúp ích cho rất nhiều người đó.

                          Comment


                          • #73
                            Nguyên văn bởi dinh_dong
                            Bác Huy cho cái đơn giá board Bác làm em với, em đang sắp làm, đi mua linh kiện, mà chưa biết khoảng bao nhiêu.
                            Bác có ở TP HCM không? Ở nhật tảo mua linh kiện ở đâu thì okey zị.? Tks bác.
                            Mình mua linh kiện tại Thiên Minh Trang chủ - Thiên Minh Electronic Solutions Hôm trước nhờ bạn mua hết đâu gần 400k
                            Có cái hóa đơn luôn nè keke
                            Attached Files

                            Email:
                            Tel: 0983.497.310

                            Comment


                            • #74
                              Nguyên văn bởi nttam79 Xem bài viết
                              Mừng quá , vậy là code mình post hướng dẫn không có gì sai. Vẫn biết là chương trình mình viết thì chạy nhưng không biết post lên có sai sót gì không và mọi người có làm theo được không.
                              @Huy: nếu đã ping được thì Webserver, điều khiển qua Internet,... chỉ là chuyện nhỏ, vì như vậy là phần hardware giao tiếp ethernet và giao thức IP đã chạy OK, còn lại sử dụng thế nào là do các bạn thôi.
                              TienHuy đúng là dân pro thiệt đó, mặc dù viết hướng dẫn nhưng mình biết tự buid được mạch và code của mình theo đó cũng là rất khó, hướng dẫn chỉ là chung chung thôi. Huy có thể thay title của file code được rồi đó .
                              Tất cả là nhờ anh thôi, bản quyền cũng là của anh mà.
                              Hardware OK là mừng rùi vì nhìu bạn có thể tự làm cho đỡ tốn kém. Hjhj
                              Port lại cái mạch vì có sửa lại kích thước chân linh kiện, Via lớn hơn và lỗi thiếu dây ở chân thạch anh 25Mhz(lúc hàn mạch mới phát hiện) để các bạn dễ ủi.
                              Attached Files
                              Last edited by tienhuypro; 11-11-2011, 01:40.

                              Email:
                              Tel: 0983.497.310

                              Comment


                              • #75
                                Giải thích cho 2 hàm chính trong giao thức TCP:
                                Hàm TCPPackedSend:
                                Code:
                                void TCPPackedSend(struct tcpSession *pSession, unsigned char Flags, unsigned int len, unsigned char *dataBuffer)
                                Trong này:
                                - pSession là con trỏ, trỏ đến struct tcpSession trong bảng TCP Session Table tương ứng với phiên kết nối TCP mà ta muốn gửi gói tin đi (trong phần lập trình giao thức TCP này, ta hỗ trợ việc AVR đồng thời theo dõi và truyền data với nhiều kết nối (nhiều client) cùng lúc).
                                - Flags là các cờ tương ứng mà ta muốn set trong header TCP
                                - len: chiều dài buffer dữ liệu ứng dụng.
                                - dataBuffer: buffer chứa dữ liệu ứng dụng.
                                Cấu trúc frame dữ liệu mà ENC28J60 sẽ gửi đi như sau:

                                Lúc này, dataBuffer đang trỏ đến phần Application Data trong frame trên, biến len đang là chiều dài phần data này.
                                Khai báo các biến sử dụng trong hàm:
                                Code:
                                	unsigned int tmp;
                                	unsigned long checksum32;
                                Lúc này, trên buffer (dataBuffer) đã có dữ liệu ứng dụng (phần Application Data), nhiệm vụ của giao thức TCP là phải xây dựng header TCP cho frame dữ liệu này.
                                Tiếp theo, ta khai báo 2 con trỏ, trỏ đến vùng IP Header và TCP Header (mới khai báo, chưa gán địa chỉ):
                                Code:
                                	struct ntTCPHeader* tcpHeader;
                                	struct ntIPHeader* ipHeader;
                                Nếu là đang trong giai đoạn thiết lập kết nối (cờ SYN được set) thì TCP Header sẽ có thêm trường Option, chứa giá trị MSS (Max Segment Size), ta ghi luôn vào vùng buffer dành cho Application Data, vì khi SYN thì vùng này không có (các bản tin thiết lập kết nối không chứa dữ liệu ứng dụng).
                                Code:
                                	if(Flags & TCP_SYN_FLAG){
                                		//Option data
                                		dataBuffer[0] = 0x02;
                                		dataBuffer[1] = 0x04;
                                		dataBuffer[2] = (MAX_SEGMENT_SIZE >> 8) & 0xff;
                                		dataBuffer[3] = MAX_SEGMENT_SIZE & 0xff;
                                		dataBuffer[4] = 0x01;
                                		dataBuffer[5] = 0x03;
                                		dataBuffer[6] = 0x03;
                                		dataBuffer[7] = 0x00;
                                	}
                                Bây giờ ta dịch lui con trỏ dataBuffer 1 đoạn bằng chiều dài TCP Header và trỏ tcpHeader đến phần đầu đoạn này.
                                Code:
                                	dataBuffer -= TCP_HEADER_LEN;
                                	tcpHeader = (struct ntTCPHeader*)dataBuffer;
                                Điền các trường cho TCP Header:
                                - Source port và Des port lấy từ thông tin về session tương ứng:
                                Code:
                                	tcpHeader->srcPort = HTONS(pSession->srcPort);
                                	tcpHeader->desPort = HTONS(pSession->desPort);
                                - Số tuần tự cũng vậy:
                                Code:
                                	tcpHeader->seqNumber = HTONL(pSession->seqNumber);
                                Sau đó ta phải tăng số tuần tự lên tùy theo chiều dài dữ liệu:
                                Code:
                                	pSession->seqNumber = pSession->seqNumber + len;
                                Lưu ý (chỗ này lúc viết code mình bị sai, debug mất cả buổi tối): tuy các bản tin SYN và FIN không chứa dữ liệu, nó vẫn được xem là có chiều dài dữ liệu 1 byte, phải tăng số tuần tự lên 1 đối với các bản tin này:
                                Code:
                                	if(Flags & (TCP_FIN_FLAG|TCP_SYN_FLAG))
                                		(pSession->seqNumber)++;
                                Số ACK:
                                Code:
                                	tcpHeader->ackNumber = HTONL(pSession->ackNumber);
                                Nếu có cờ SYN, như đã nói trên Header TCP sẽ có trường Option chiều dài 8 byte, do đó ta phải ghi giá trị tương ứng cho trường Offset, và tăng biến len lên tương ứng:
                                Code:
                                	if(Flags & TCP_SYN_FLAG){
                                		tcpHeader->Offset = (0x07<<4);
                                		len += (TCP_HEADER_LEN + 8);
                                Nếu không, chiều dài TCP Header là mặc định (đã định nghĩa TCP_HEADER_LEN)
                                Code:
                                	}else{
                                		tcpHeader->Offset = (0x05<<4);
                                		len += TCP_HEADER_LEN;
                                	}
                                Ghi giá trị các cờ
                                Code:
                                	tcpHeader->Flags = Flags;
                                Giá trị trường Window
                                Code:
                                	tcpHeader->Window = HTONS(pSession->srcWin);//((NETSTACK_BUFFERSIZE-20-14));
                                Tạm thời gán checksum = 0 (ta sẽ tính TCP checksum sau)
                                Code:
                                	tcpHeader->Checksum = 0;
                                Con trỏ khẩn không sử dụng:
                                Code:
                                	tcpHeader->UrgentPtr = 0x0000;
                                Trỏ đến biến con trỏ ipHeader đến vùng IP Header trên buffer:
                                Code:
                                	ipHeader = (struct ntIPHeader*)(dataBuffer-IP_HEADER_LEN);
                                Gán tạm thời 1 số giá trị cần thiết cho IP Header để tính checksum:
                                Code:
                                	ipHeader->srcIPAddr = HTONL(ipGetConfig()->ip);
                                	ipHeader->desIPAddr = HTONL(pSession->desIP);
                                	ipHeader->Checksum = HTONS(len);
                                	ipHeader->TTL = 0x00;
                                	ipHeader->Protocol = IP_PROTO_TCP;
                                Ở đây các bạn cần tìm hiểu thêm cách tính checksum TCP, nó không chỉ tính checksum phần TCP Header và dữ liệu mà còn tính thêm 1 số trường của IP trong 1 header IP giả, do đó ta phải gán tạm các trường này lên buffer thì mới tính được TCP checksum, còn thật ra Header IP xuống giao thức IP sẽ được xây dựng lại (hàm ipSend).
                                Tính checksum và ghi vào trường checksum của Header TCP
                                Code:
                                	checksum32 = 0;
                                	tmp = len + 12;
                                	tmp = checksum (((unsigned char *)ipHeader+8), tmp, checksum32);
                                	tcpHeader->Checksum = HTONS(tmp);
                                Gọi hàm ipSend để yêu cầu giao thức IP gửi gói tin đi.
                                Code:
                                	ipSend(pSession->desIP, IP_PROTO_TCP, len, (unsigned char *)tcpHeader);

                                Comment

                                Về tác giả

                                Collapse

                                nttam79 Tìm hiểu thêm về nttam79

                                Bài viết mới nhất

                                Collapse

                                Đang tải...
                                X