00001 /******************************************************************************* 00002 enc28j60_tcp_fsm.c: Stavovy automat TCP 00003 Copyright (C) 2010 Brno University of Technology, 00004 Faculty of Information Technology 00005 Author(s): Martin Musil <xmusil34 AT fit.vutbr.cz> 00006 00007 LICENSE TERMS 00008 00009 Redistribution and use in source and binary forms, with or without 00010 modification, are permitted provided that the following conditions 00011 are met: 00012 1. Redistributions of source code must retain the above copyright 00013 notice, this list of conditions and the following disclaimer. 00014 2. Redistributions in binary form must reproduce the above copyright 00015 notice, this list of conditions and the following disclaimer in 00016 the documentation and/or other materials provided with the 00017 distribution. 00018 3. All advertising materials mentioning features or use of this software 00019 or firmware must display the following acknowledgement: 00020 00021 This product includes software developed by the University of 00022 Technology, Faculty of Information Technology, Brno and its 00023 contributors. 00024 00025 4. Neither the name of the Company nor the names of its contributors 00026 may be used to endorse or promote products derived from this 00027 software without specific prior written permission. 00028 00029 This software or firmware is provided ``as is'', and any express or implied 00030 warranties, including, but not limited to, the implied warranties of 00031 merchantability and fitness for a particular purpose are disclaimed. 00032 In no event shall the company or contributors be liable for any 00033 direct, indirect, incidental, special, exemplary, or consequential 00034 damages (including, but not limited to, procurement of substitute 00035 goods or services; loss of use, data, or profits; or business 00036 interruption) however caused and on any theory of liability, whether 00037 in contract, strict liability, or tort (including negligence or 00038 otherwise) arising in any way out of the use of this software, even 00039 if advised of the possibility of such damage. 00040 00041 $Id$ 00042 00043 *******************************************************************************/ 00044 00045 #include "enc28j60_spi.h" 00046 #include "enc28j60_ip.h" 00047 #include "enc28j60_tcp.h" 00048 00049 extern unsigned long dest_seq_num; 00050 extern unsigned long local_seq_num; 00051 extern unsigned long expected_ack_num; 00052 unsigned int dest_window_size; 00053 unsigned int tcp_retransmit_timer; 00054 unsigned int tcp_fsm_timer; 00055 00056 struct ip_h* ip_header_ptr; 00057 00058 extern struct tcp_socket socket; 00059 00060 //************************************ 00061 //TCP stavovy automat 00062 //************************************ 00066 char tcp_fsm(struct tcp_h * tcp_header){ 00067 00068 switch(socket.state){ 00069 00070 case FSM_IDLE: 00071 tcp_fsm_timer = SYN_TIMEOUT; 00072 break; 00073 00074 //*************************************** 00075 case FSM_NOT_CONNECTED: 00076 00077 if(tcp_header != NULL){ 00078 00079 if( tcp_header->flags == (TCP_SYN | TCP_ACK)){ 00080 00081 dest_seq_num = NTOHL(tcp_header->seq_num); 00082 dest_window_size = NTOHS(tcp_header->window_size); 00083 00084 //prechod do stavu SYN 00085 tcp_retransmit_timer = MAX_RETRANSMIT; 00086 socket.state = FSM_ESTABILISHED; 00087 dest_seq_num++; 00088 local_seq_num++; 00089 expected_ack_num = local_seq_num; 00090 00091 tcp_retransmit_timer = MAX_RETRANSMIT; 00092 //poslani ACK 00093 return tcp_send_header(TCP_ACK); 00094 } 00095 else if( ((tcp_header->flags) & TCP_RST) > 0 ){ 00096 tcp_fsm_reset(); 00097 return -1; 00098 } 00099 else{ 00100 return tcp_send_header(TCP_RST); 00101 } 00102 00103 } 00104 //volání FSM časovačem 00105 else{ 00106 tcp_fsm_timer--; 00107 if(tcp_fsm_timer == 0 ){ 00108 tcp_fsm_reset(); 00109 } 00110 00111 local_seq_num = 0; 00112 dest_seq_num = 0; 00113 00114 //poslani SYN 00115 00116 return tcp_send_header(TCP_SYN); 00117 00118 } 00119 00120 break; 00121 00122 //*************************************** 00123 case FSM_LISTEN: 00124 00125 if(tcp_header != NULL){ 00126 //prijeti SYN paketu 00127 if( tcp_header->flags == TCP_SYN ){ 00128 00129 socket.dest_port = NTOHS(tcp_header->src_port); 00130 socket.dest_ip = NTOHL(ip_header_ptr->src_ip); 00131 dest_seq_num = NTOHL(tcp_header->seq_num); 00132 local_seq_num = 0; 00133 dest_window_size = NTOHS(tcp_header->window_size); 00134 00135 //prechod do stavu SYN 00136 socket.state = FSM_SYN; 00137 dest_seq_num++; 00138 00139 tcp_fsm_timer = SYN_TIMEOUT; 00140 //poslani SYN_ACK 00141 return tcp_send_header(TCP_SYN | TCP_ACK); 00142 } 00143 else{ 00144 return tcp_send_header(TCP_RST); 00145 } 00146 } 00147 //volání FSM časovačem 00148 else return 0; 00149 00150 break; 00151 00152 //*************************************** 00153 case FSM_SYN: 00154 if(tcp_header != NULL){ 00155 00156 tcp_fsm_timer = SYN_TIMEOUT; 00157 if( tcp_header->flags == TCP_ACK ){ 00158 local_seq_num++; 00159 00160 tcp_retransmit_timer = MAX_RETRANSMIT; 00161 socket.state = FSM_ESTABILISHED; 00162 expected_ack_num = local_seq_num; 00163 tx_unlock(TX3); 00164 return 0; 00165 } 00166 //prichod RST 00167 if( ((tcp_header->flags) & TCP_RST) > 0 ){ 00168 tcp_fsm_reset(); 00169 return -1; 00170 } 00171 00172 } 00173 //volání FSM časovačem 00174 else{ 00175 tcp_fsm_timer--; 00176 if(tcp_fsm_timer == 0 ){ 00177 tcp_fsm_reset(); 00178 } 00179 00180 //poslani SYN_ACK 00181 return tcp_send_header(TCP_SYN | TCP_ACK); 00182 00183 } 00184 break; 00185 00186 //*************************************** 00187 //spojeni navazano 00188 case FSM_ESTABILISHED: 00189 00190 //*************************************** 00191 //polouzavrene spojeni - protejsek jeste smi posilat data 00192 case FSM_HALF_OPEN: 00193 00194 //prichozi paket 00195 if(tcp_header != NULL){ 00196 00197 //preposilani paketu, druha strana nedostala ACK, poslu ACK znovu 00198 if(HTONL(tcp_header->seq_num) < dest_seq_num){ 00199 00200 return tcp_send_header(TCP_ACK); 00201 } 00202 00203 //trideni podle flagu 00204 switch(tcp_header->flags){ 00205 00206 //prichozi SYN ACK - ACK paket z 3-way handshake nebyl dorucen 00207 case (TCP_SYN | TCP_ACK): 00208 00209 if(socket.state == FSM_ESTABILISHED){ 00210 00211 return tcp_send_header(TCP_ACK); 00212 00213 } 00214 else if(socket.state == FSM_HALF_OPEN){ 00215 00216 return tcp_send_header(TCP_RST); 00217 } 00218 break; 00219 00220 case TCP_ACK: 00221 00222 //datova cast paketu je vetsi jak 0 -> prichozi data 00223 if(rx_left() > 0){ 00224 if(dest_seq_num != NTOHL(tcp_header->seq_num)){ 00225 //sekvencni cisla nesedi, data nedosla v poradi, odeslu potvrzeni poslednich prijatych dat 00226 return tcp_send_header(TCP_ACK); 00227 } 00228 dest_seq_num += rx_left(); 00229 //odeslani ACK 00230 tcp_send_header(TCP_ACK); 00231 //zavolani handleru 00232 (*(socket.app_handler))((struct ip_h *)&ip_header_ptr,(struct tcp_h *) &tcp_header); 00233 } 00234 00235 if(expected_ack_num == NTOHL(tcp_header->ack_num)){ //ACK cislo sedi, posledni paket potvrzen 00236 tcp_retransmit_timer = MAX_RETRANSMIT; 00237 local_seq_num = expected_ack_num; 00238 tx_unlock(TX3); 00239 } 00240 //patri ke stavu FSM_HALF_OPEN - potvrzeni posledniho datoveho paketu v pripade, ze jiz byl poslan i paket FIN ACK(ten se totiz pocita za 1 bajt) 00241 else if((socket.state == FSM_HALF_OPEN) & ((expected_ack_num - 1) == NTOHL(tcp_header->ack_num))){ 00242 tcp_fsm_timer = FIN_WAIT1_TIMEOUT; 00243 local_seq_num = expected_ack_num - 1; 00244 tx_unlock(TX3); 00245 } 00246 else{ 00247 return -1; 00248 } 00249 00250 00251 break; 00252 00253 //prichod RST - okamzite ukonceni spojeni 00254 case TCP_RST: 00255 case (TCP_RST | TCP_ACK): 00256 00257 tcp_fsm_reset(); 00258 return 0; 00259 00260 //nová data + potvrzení přijetí 00261 case (TCP_PSH | TCP_ACK): 00262 00263 //kontrola,zda ocekavane ACK cislo bylo prijato 00264 if(expected_ack_num == NTOHL(tcp_header->ack_num)){ //ACK cislo sedi, posledni paket potvrzen 00265 tcp_retransmit_timer = MAX_RETRANSMIT; 00266 local_seq_num = expected_ack_num; 00267 tx_unlock(TX3); 00268 } 00269 //patri ke stavu FSM_HALF_OPEN - potvrzeni posledniho datoveho paketu v pripade, ze jiz byl poslan i paket FIN ACK(ten se totiz pocita za 1 bajt) 00270 else if((socket.state == FSM_HALF_OPEN) & ((expected_ack_num - 1) == NTOHL(tcp_header->ack_num))){ 00271 tcp_fsm_timer = FIN_WAIT1_TIMEOUT; 00272 local_seq_num = expected_ack_num - 1; 00273 tx_unlock(TX3); 00274 } 00275 else{ 00276 return -1; 00277 } 00278 00279 //nová data 00280 case TCP_PSH: 00281 00282 if(dest_seq_num != NTOHL(tcp_header->seq_num)){ 00283 return tcp_send_header(TCP_ACK); 00284 } 00285 00286 dest_seq_num += rx_left(); 00287 00288 //odeslani ACK 00289 tcp_send_header(TCP_ACK); 00290 //zavolani handleru 00291 (*(socket.app_handler))((struct ip_h *)&ip_header_ptr,(struct tcp_h *) &tcp_header); 00292 break; 00293 00294 //ukončení spojení (paket může obsahovat i data a potvrzení přijetí paketu) 00295 case (TCP_PSH | TCP_ACK | TCP_FIN): 00296 case (TCP_FIN | TCP_ACK): 00297 00298 //datova cast paketu je vetsi jak 0 -> prichozi data 00299 if(rx_left() > 0){ 00300 if(dest_seq_num != NTOHL(tcp_header->seq_num)){ 00301 //sekvencni cisla nesedi, data nedosla v poradi, odeslu potvrzeni poslednich prijatych dat 00302 return tcp_send_header(TCP_ACK); 00303 } 00304 dest_seq_num += rx_left(); 00305 //zavolani handleru 00306 (*(socket.app_handler))((struct ip_h *)&ip_header_ptr,(struct tcp_h *) &tcp_header); 00307 } 00308 00309 00310 if(expected_ack_num != NTOHL(tcp_header->ack_num)){ 00311 if( dest_seq_num == NTOHL(tcp_header->seq_num)){ 00312 //return tcp_send_header(TCP_ACK); 00313 return -1; 00314 } 00315 } 00316 else{ 00317 tcp_retransmit_timer = MAX_RETRANSMIT; 00318 local_seq_num = expected_ack_num; 00319 tx_unlock(TX3); 00320 } 00321 00322 //ukončení spojení 00323 case TCP_FIN: 00324 00325 dest_seq_num++; 00326 00327 if(socket.state == FSM_ESTABILISHED){ 00328 00329 socket.state = FSM_CLOSE_WAIT; 00330 tcp_fsm_timer = CLOSE_WAIT_TIMEOUT; 00331 expected_ack_num = local_seq_num +1; //+1 za odesilany FIN 00332 //odeslani FIN ACK 00333 tcp_send_header(TCP_FIN | TCP_ACK); 00334 } 00335 else if(socket.state == FSM_HALF_OPEN){ 00336 //odesle posledni potvrzovaci paket 00337 tcp_send_header(TCP_ACK); 00338 00339 expected_ack_num = local_seq_num; 00340 tcp_fsm_timer = TIME_WAIT_TIMEOUT; 00341 socket.state = FSM_TIME_WAIT; 00342 } 00343 break; 00344 } 00345 } 00346 00347 00348 //volání FSM časovačem 00349 else{ 00350 if(socket.state == FSM_ESTABILISHED){ 00351 // preposlani nepotvrzeneho paketu 00352 if(expected_ack_num != local_seq_num){ 00353 if(tcp_retransmit_timer-- == 0) //paket se delsi dobu nedari dorucit - ukonceni spojeni 00354 tcp_fsm_reset(); 00355 00356 tx_load(TX3); 00357 return tcp_out(local_seq_num, dest_seq_num, TCP_PSH | TCP_ACK); 00358 } 00359 } 00360 else if(socket.state == FSM_HALF_OPEN){ 00361 // preposlani nepotvrzenych paketu 00362 if(expected_ack_num != local_seq_num){ 00363 00364 if((expected_ack_num - 1) != local_seq_num ){ //nepotvrzena data 00365 if(tcp_retransmit_timer-- == 0) //paket se delsi dobu nedari dorucit - ukonceni spojeni 00366 tcp_fsm_reset(); 00367 00368 tx_load(TX3); 00369 tcp_out(local_seq_num, dest_seq_num, TCP_PSH | TCP_ACK); 00370 } 00371 00372 //nepotvrzen FIN 00373 tcp_fsm_timer--; 00374 if(tcp_fsm_timer == 0 ){ 00375 tcp_fsm_reset(); 00376 } 00377 //odeslani FIN/ACK zpravy, aktivni ukonceni spojeni 00378 tcp_send_header(TCP_FIN | TCP_ACK); 00379 00380 } 00381 00382 } 00383 } 00384 break; 00385 00386 00387 00388 //*************************************** 00389 case FSM_CLOSE_WAIT: 00390 00391 //prichozi paket 00392 if(tcp_header != NULL){ 00393 tcp_fsm_timer = CLOSE_WAIT_TIMEOUT; 00394 //konec spojeni 00395 if( tcp_header->flags == TCP_ACK){ 00396 00397 if(expected_ack_num != NTOHL(tcp_header->ack_num)){ //ACK cislo nesedi, posledni paket nepotvrzen 00398 return -1; 00399 } 00400 tcp_retransmit_timer = MAX_RETRANSMIT; 00401 local_seq_num = expected_ack_num; 00402 tx_unlock(TX3); 00403 00404 tcp_fsm_reset(); 00405 break; 00406 } 00407 00408 else if( ((tcp_header->flags) & TCP_RST) > 0 ){ 00409 00410 tcp_fsm_reset(); 00411 break; 00412 } 00413 00414 } 00415 //volání FSM časovačem 00416 else{ 00417 // preposlani nepotvrzeneho paketu 00418 if(expected_ack_num != (local_seq_num + 1)){ //kvuli expected_ack_num = local_seq_num+1; ve TCP_ESTABILISHED, prijem FIN paketu 00419 if(tcp_retransmit_timer-- == 0) //paket se delsi dobu nedari dorucit - ukonceni spojeni 00420 tcp_fsm_reset(); 00421 00422 tx_load(TX3); 00423 return tcp_out(local_seq_num, dest_seq_num, TCP_PSH | TCP_ACK); 00424 } 00425 else{ 00426 tcp_fsm_timer--; 00427 if(tcp_fsm_timer == 0 ){ 00428 tcp_fsm_reset(); 00429 } 00430 return tcp_send_header(TCP_FIN | TCP_ACK); 00431 } 00432 } 00433 00434 00435 00436 //*************************************** 00437 case FSM_TIME_WAIT: 00438 00439 //dosel paket od protejsku, musime preposlat ACK paket 00440 if(tcp_header != NULL){ 00441 00442 tcp_fsm_timer = TIME_WAIT_TIMEOUT; 00443 00444 if( ((tcp_header->flags) & TCP_RST) > 0 ){ 00445 tcp_fsm_reset(); 00446 return 0; 00447 } 00448 //odesle posledni potvrzovaci paket 00449 return tcp_send_header(TCP_ACK); 00450 } 00451 //volání FSM časovačem 00452 else{ 00453 //timeout, az vyprsi,muzeme ukoncit spojeni 00454 tcp_fsm_timer--; 00455 if(tcp_fsm_timer == 0 ){ 00456 tcp_fsm_reset(); 00457 } 00458 } 00459 break; 00460 00461 default: 00462 return -1; 00463 } 00464 00465 return 0; 00466 }