FITkit
Fakulta informačních technologií

enc28j60_tcp_fsm.c

Zobrazit dokumentaci tohoto souboru.
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 }