📄 tcp.c
字号:
/*,-----------------------------------------------------------------------------------------.| net/tcp|-----------------------------------------------------------------------------------------| this file implements a very basic tcp protocol| - very basic|| KNOWN PROBLEMS:| - it does not yet check the tcp checksum of incoming packets!!| - something with the seq/ack calc might be buggy| -> must be checked by sending bad tcp packets/re-request etc [[TODO!]]|| Author : Simon Schulz / avr{AT}auctionant.de|| ||-----------------------------------------------------------------------------------------| License:| This program is free software; you can redistribute it and/or modify it under| the terms of the GNU General Public License as published by the Free Software| Foundation; either version 2 of the License, or (at your option) any later| version.| This program is distributed in the hope that it will be useful, but|| WITHOUT ANY WARRANTY;|| without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR| PURPOSE. See the GNU General Public License for more details.|| You should have received a copy of the GNU General Public License along with| this program; if not, write to the Free Software Foundation, Inc., 51| Franklin St, Fifth Floor, Boston, MA 02110, USA|| http://www.gnu.de/gpl-ger.html`-----------------------------------------------------------------------------------------*/#include "tcp.h"//ACTIVATE DEBUG by editing this file:#include "debug.h"struct tcp_socket tcp_sockets[TCP_SOCKET_COUNT];//initialise all sockets to closed state:void tcp_init(){ unsigned char i = 0; for(i=0; i<TCP_SOCKET_COUNT; i++){ tcp_close_socket(i); }}unsigned char tcp_find_free_socket(){ unsigned char i; for(i=0; i<TCP_SOCKET_COUNT; i++){ if (tcp_sockets[i].state == TCP_STATE_CLOSED) return i; } //no free closed socket fount! -> kick an TIMED_WAIT socket for(i=0; i<TCP_SOCKET_COUNT; i++){ if (tcp_sockets[i].state == TCP_STATE_TIMED_WAIT){ tcp_close_socket(i); return i; } } //no more free sockets ... return invalid val return(TCP_SOCKET_COUNT);}void tcp_packet_in(unsigned char *buffer, unsigned int len){ unsigned char tcp_header_flags; unsigned int source_port; unsigned int dest_port; unsigned int datalen; unsigned int datapos; unsigned long source_ip; unsigned long longtmp; unsigned char socketnum; //unsigned char i; //read header: //source ip: source_ip = nic_buffer_to_ip(&buffer[IP_POS_SRC_IP]); //source port: source_port = (buffer[TCP_POS_SRC_PORT]<<8) | buffer[TCP_POS_SRC_PORT+1]; //dest port dest_port = (buffer[TCP_POS_DST_PORT]<<8) | buffer[TCP_POS_DST_PORT+1]; //flags: tcp_header_flags = buffer[TCP_POS_HEADERFLAGS] & 0x3F; //check if target ip matches: if (nic_buffer_to_ip(&buffer[IP_POS_DST_IP]) != nic_ip){ #if TCP_DEBUG softuart_puts_progmem("TCP : ignoring packet for ip "); softuart_put_ip(nic_buffer_to_ip(&buffer[IP_POS_DST_IP])); softuart_putnewline(); #endif return; //no, not for us ! } //do we have an open socket for this connection ?! for(socketnum=0; socketnum<TCP_SOCKET_COUNT; socketnum++){ //check every not closed socket if (tcp_sockets[socketnum].state != TCP_STATE_CLOSED){ //compare source port (faster check than source ip if(tcp_sockets[socketnum].source_port == source_port){ //now compare the source ip: if(tcp_sockets[socketnum].source_ip == source_ip){ /// yes, this is for us ! //handle packet #if TCP_DEBUG softuart_puts_progmem("TCP : socket["); softuart_put_uint8(socketnum); softuart_puts_progmem("] ACK: "); softuart_put_uint16(nic_buffer_to_seq(&buffer[TCP_POS_ACK])&0xFFFF); softuart_puts_progmem(" SEQ: "); softuart_put_uint16(nic_buffer_to_seq(&buffer[TCP_POS_SEQ])&0xFFFF); softuart_puts_progmem(" -> "); #endif //reset TTL: tcp_sockets[socketnum].ttl = TCP_TTL_TIMEOUT; //check for connection abort (RST flag) if (tcp_header_flags & TCP_RST_FLAG){ //client wants to terminate ! accept this... tcp_close_socket(socketnum); //tcp_sockets[socketnum].ack = nic_buffer_to_seq(&buffer[TCP_POS_SEQ]) + 1; //tcp_sockets[socketnum].seq = nic_buffer_to_seq(&buffer[TCP_POS_ACK]); //FIXME: what is the correct response to an RST packet ?! #if TCP_DEBUG softuart_puts_progmem(" RST FLAG received -> socket CLOSED.\r\n"); #endif return; } switch (tcp_sockets[socketnum].state){ ///SNY_RECEIVED case(TCP_STATE_SYN_RECEIVED): if (tcp_header_flags == TCP_ACK_FLAG){ //ok, this connection is established: //we do not need to send any data now) tcp_sockets[socketnum].state = TCP_STATE_ESTABLISHED; #if TCP_DEBUG softuart_puts_progmem("ESTABLISHED"); #endif }else{ //invalid packet or TCP_RST_FLAG for example ... //connection reset -> close socket tcp_close_socket(socketnum); #if TCP_DEBUG softuart_puts_progmem("CLOSED"); #endif } break; ///ESTABLISHED case(TCP_STATE_ESTABLISHED): if (tcp_header_flags & TCP_FIN_FLAG){ //connection close request //-------send ACK & goto CLOSE_WAIT---- no do this: //send ACK+FIN and goto LAST ACK: tcp_sockets[socketnum].state = TCP_STATE_LAST_ACK; tcp_sockets[socketnum].ack = nic_buffer_to_seq(&buffer[TCP_POS_SEQ]) + 1; tcp_sockets[socketnum].seq = nic_buffer_to_seq(&buffer[TCP_POS_ACK]); tcp_send_packet(buffer, socketnum, (TCP_FIN_FLAG|TCP_ACK_FLAG), 0); #if TCP_DEBUG softuart_puts_progmem("LAST_ACK"); #endif }else{ //this is data for application! //check for error & send packet to correct application ///OUTGOING DATA HANDLING: //which databyte was acked ? longtmp = nic_buffer_to_seq(&buffer[TCP_POS_ACK]); //the last packet we have sent was tcp_sockets[socketnum].seq, //check it: if ((longtmp != tcp_sockets[socketnum].seq) && (longtmp != 1)){ #if TCP_DEBUG softuart_puts_progmem("TCP : ack != last seqnum! retransmit : "); softuart_put_uint16(longtmp&0xFFFF); softuart_putc(' '); softuart_put_uint16(tcp_sockets[socketnum].seq&0xFFFF); softuart_putc(' '); softuart_putnewline(); #endif //overwrite seq num -> send acked data ! tcp_sockets[socketnum].seq = longtmp; } //update our seq counter, we should send now //databyte longtmp-1 (1 = initval of seq counter) //tcp_sockets[socketnum].seq = longtmp; ///INCOMING DATA HANDLING: //check if this is the data we expect: longtmp = nic_buffer_to_seq(&buffer[TCP_POS_SEQ]); //extract data pos: datapos = (14 + ((buffer[IP_POS_VERSION] & 0x0F) << 2) + ((buffer[TCP_POS_DATA_OFFSET] & 0xF0) >>2)); datalen = ((buffer[IP_POS_PKTLEN+0]<<8) | buffer[IP_POS_PKTLEN+1])-datapos+14; //we are waiting for a packet with seq = <tcp_sockets[socketnum].ack> //-> we sent an ack for packet byte n, now the seq counter of incoming // packet has to be <n> if ((longtmp != tcp_sockets[socketnum].ack) && (tcp_sockets[socketnum].ack != 0)){ //there was an error, check what to do next: if (longtmp < tcp_sockets[socketnum].ack){ //we expected data x to y but we got (x-n) to y //we onlny need x to y, so discard n bytes: longtmp = (tcp_sockets[socketnum].ack - longtmp); datapos = datapos + longtmp; datalen = datalen - longtmp; #if TCP_DEBUG softuart_puts_progmem(" WARN: tcp data dup! ignoring duplicate data. "); #endif }else{ //longtmp > tcp.... //uups one packet was lost during transfer ! //re request this packet, send an ack for expected <seq>: #if TCP_DEBUG softuart_puts_progmem(" ERR : tcp packet lost! re-requesting. "); #endif tcp_send_packet(buffer, socketnum, (TCP_ACK_FLAG), 0); return; } } //protect buffer: if (datapos > NIC_BUFFERSIZE) datapos = NIC_BUFFERSIZE; if ((datapos + datalen) > NIC_BUFFERSIZE) datalen = 0; //limit datalength to length that fits into our buffer: if (datalen > (NIC_BUFFERSIZE-datapos)) datalen = (NIC_BUFFERSIZE-datapos); //next ack packet we will send must ack data byte n+datalen: tcp_sockets[socketnum].ack = tcp_sockets[socketnum].ack + (datalen); #if TCP_DEBUG softuart_put_uint16(datalen); softuart_puts_progmem(" bytes in "); /*if (datalen>0) softuart_putnewline(); for(int d=datapos; d<datapos+datalen; d++){ softuart_putc(buffer[d]); }*/ softuart_putnewline(); #endif //now call the application unsigned char appstate = TCP_APPSTATE_NONE; unsigned int data_tx_count = 0; if ((tcp_sockets[socketnum].dest_port == IP_PORT_HTTPD)||(tcp_sockets[socketnum].dest_port == 3333)){ data_tx_count = httpd_data_in(buffer, datapos, datalen, socketnum, &appstate); //}else{ // data_tx_count = http_client_data_in(buffer, datapos, datalen, socketnum, &appstate); } //application modified appstate switch(appstate){ case (TCP_APPSTATE_EMPTYACK): tcp_send_packet(buffer, socketnum, (TCP_ACK_FLAG), 0); tcp_sockets[socketnum].seq = tcp_sockets[socketnum].seq; break; case (TCP_APPSTATE_HAS_TXDATA): //send data tcp_send_packet(buffer, socketnum, (TCP_ACK_FLAG), data_tx_count); //seq counter update: tcp_sockets[socketnum].seq = tcp_sockets[socketnum].seq + data_tx_count; #if TCP_DEBUG softuart_puts_progmem("TCP : last byte sent = "); softuart_put_uint16(tcp_sockets[socketnum].seq&0xFFFF); softuart_putc(' '); #endif break; case (TCP_APPSTATE_FINISHED): #if TCP_DEBUG softuart_puts_progmem("TCP : app closed socket "); softuart_put_uint8(socketnum); #endif tcp_sockets[socketnum].state = TCP_STATE_FIN_WAIT1; tcp_send_packet(buffer, socketnum, (TCP_FIN_FLAG|TCP_PSH_FLAG|TCP_ACK_FLAG), 0); //seq counter update: tcp_sockets[socketnum].seq = tcp_sockets[socketnum].seq + 1; break; default: //do nothing... should not happen! break; } } break; ///CLOSE WAIT case(TCP_STATE_CLOSE_WAIT): //goto last_ack & send FIN packet tcp_sockets[socketnum].state = TCP_STATE_LAST_ACK; tcp_sockets[socketnum].ack = nic_buffer_to_seq(&buffer[TCP_POS_SEQ])+1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -