Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

tcp.c

Go to the documentation of this file.
00001 /*!     \file network/tcp.c
00002  *      \brief TCP (Transmition Control Protocol) layer.
00003  *      \author Andrea Righi <drizzt@inwind.it>
00004  *      \date Last update:\n
00005  *              2003-01-21 Andrea Righi:
00006  *                      Suppressed deferencing type-punned pointer
00007  *                      warning.
00008  *      \note Copyright (&copy;) 2003 Andrea Righi
00009  *
00010  *      \todo
00011  *      Complete the states machine for the TCP connections.
00012  */
00013 
00014 #include <const.h>
00015 
00016 #include <arch/mem.h>
00017 
00018 #include <kernel/clock.h>
00019 #include <kernel/console.h>
00020 #include <kernel/speaker.h>
00021 #include <kernel/kmalloc.h>
00022 #include <kernel/semaphore.h>
00023 
00024 #include <net/ip.h>
00025 #include <net/network.h>
00026 
00027 #include <net/tcp.h>
00028 
00029 //! \brief Calculate the TCP checksum.
00030 //! \param buff The TCP packet.
00031 //! \param len The size of the TCP packet.
00032 //! \param src_addr The IP source address (in network format).
00033 //! \param dest_addr The IP destination address (in network format).
00034 //! \return The result of the checksum.
00035 uint16_t tcp_checksum(const void *buff, size_t len, in_addr_t src_addr, in_addr_t dest_addr)
00036 {
00037         const uint16_t *buf=buff;
00038         uint16_t *ip_src=(void *)&src_addr, *ip_dst=(void *)&dest_addr;
00039         uint32_t sum;
00040         size_t length=len;
00041 
00042         // Calculate the sum                                            //
00043         sum = 0;
00044         while (len > 1)
00045         {
00046                 sum += *buf++;
00047                 if (sum & 0x80000000)
00048                         sum = (sum & 0xFFFF) + (sum >> 16);
00049                 len -= 2;
00050         }
00051 
00052         if ( len & 1 )
00053                 // Add the padding if the packet lenght is odd          //
00054                 sum += *((uint8_t *)buf);
00055 
00056         // Add the pseudo-header                                        //
00057         sum += *(ip_src++);
00058         sum += *ip_src;
00059         sum += *(ip_dst++);
00060         sum += *ip_dst;
00061         sum += htons(IPPROTO_TCP);
00062         sum += htons(length);
00063 
00064         // Add the carries                                              //
00065         while (sum >> 16)
00066                 sum = (sum & 0xFFFF) + (sum >> 16);
00067 
00068         // Return the one's complement of sum                           //
00069         return ( (uint16_t)(~sum)  );
00070 }
00071 
00072 void connect_sound()
00073 {
00074 // Beeps when a TCP connection is opened                                //
00075         sound(0x580);
00076         delay(20);
00077 
00078         nosound();
00079 }
00080 
00081 void disconnect_sound()
00082 {
00083 // Beeps when a TCP connection is closed                                //
00084         sound(0x420);
00085         delay(20);
00086 
00087         nosound();
00088 }
00089 
00090 tcp_state_t *tcp_conn=NULL;
00091 semaphore_t tcp_mutex;
00092 
00093 void to_tcp_layer(tcp_t *packet, size_t len, in_addr_t ip_src, in_addr_t ip_dst)
00094 {
00095 // Process a TCP packet from the IP layer                               //
00096         int i;
00097         uint8_t *data_buf =     ((uint8_t *)packet) +
00098                                 (packet->tcp_hdr_len * sizeof(dword));
00099         bool chk;
00100 
00101         // Calculate the checksum                                       //
00102         chk = tcp_checksum(
00103                         packet,
00104                         len,
00105                         ip_src,
00106                         ip_dst
00107                         );
00108         if ( chk )
00109         {
00110                 kprintf("\n\rTCP checksum error! %04X", chk);
00111                 return;
00112         }
00113 
00114         DOWN(&tcp_mutex);
00115 
00116         // Dump the UDP packet                                          //
00117         kprintf(        "\n\rTCP packet received: %u(%u) bytes"
00118                 "\n\rsender  = %u.%u.%u.%u:%u"
00119                 "\n\rreceiver= %u.%u.%u.%u:%u"
00120                 "\n\rseq=%u, ack=%u, win=%u",
00121                 len - (packet->tcp_hdr_len)*sizeof(dword),
00122                 len,
00123 
00124                 IP_A(ntohl(ip_src)), IP_B(ntohl(ip_src)),
00125                 IP_C(ntohl(ip_src)), IP_D(ntohl(ip_src)),
00126                 ntohs(packet->tcp_src),
00127 
00128                 IP_A(ntohl(ip_dst)), IP_B(ntohl(ip_dst)),
00129                 IP_C(ntohl(ip_dst)), IP_D(ntohl(ip_dst)),
00130                 ntohs(packet->tcp_dst),
00131 
00132                 ntohl(packet->tcp_seq_num), ntohl(packet->tcp_ack_num),
00133                 ntohs(packet->tcp_win_size)
00134         );
00135 
00136         // Dump the flags                                               //
00137         kprintf("\n\rURG:%u ACK:%u PSH:%u RST:%u SYN:%u FIN:%u",
00138                 packet->tcp_urg,
00139                 packet->tcp_ack,
00140                 packet->tcp_psh,
00141                 packet->tcp_rst,
00142                 packet->tcp_syn,
00143                 packet->tcp_fin
00144         );
00145 
00146         kprintf("\n\rData:\n\r");
00147         for(i=0; i<(len-packet->tcp_hdr_len*4); i++)
00148                 kputchar( data_buf[i]  );
00149 
00150         if ( (packet->tcp_syn) && (tcp_conn!=NULL))
00151         {
00152                 // For now only one connection is allowed :-(           //
00153                 kprintf("\n\rOnly one TCP connection is allowed!");
00154 
00155                 // Send an RST                                          //
00156                 packet->tcp_ack_num = htonl(ntohl(packet->tcp_seq_num) + len - packet->tcp_hdr_len*4 + 1);
00157                 packet->tcp_seq_num = tcp_conn->seq_num;
00158                 packet->tcp_hdr_len = 5;
00159                 len = sizeof(tcp_t);
00160                 packet->tcp_ack = 1;
00161                 packet->tcp_rst = 1;
00162                 packet->tcp_syn = 0;
00163                 packet->tcp_chk = 0;
00164                 packet->tcp_chk = tcp_checksum(packet, len, ip_dst, ip_src);
00165                 send_ip_packet(ip_src, packet, len, 255, IPPROTO_TCP);
00166 
00167                 UP(&tcp_mutex);
00168                 return;
00169         }
00170 
00171         if ( (packet->tcp_syn) && !(packet->tcp_ack) && (tcp_conn==NULL) )
00172         {
00173                 // SYN received!                                        //
00174                 // Open a new connection using sockets                  //
00175                 tcp_conn = kmalloc(sizeof(tcp_state_t));
00176                 memset(tcp_conn, 0, sizeof(tcp_state_t));
00177 
00178                 tcp_conn->socket.ip_src = ip_src;
00179                 tcp_conn->socket.port_src = packet->tcp_src;
00180                 tcp_conn->socket.ip_dst = ip_dst;
00181                 tcp_conn->socket.port_dst = packet->tcp_dst;
00182                 tcp_conn->state = TCP_SYN_RCVD;
00183 
00184                 // Send SYN + ACK (seq+1)                               //
00185                 // Swap source and destination ports                    //
00186                 packet->tcp_dst ^= packet->tcp_src;
00187                 packet->tcp_src ^= packet->tcp_dst;
00188                 packet->tcp_dst ^= packet->tcp_src;
00189 
00190                 packet->tcp_ack_num = htonl(ntohl(packet->tcp_seq_num) + 1);
00191                 packet->tcp_seq_num = tcp_conn->seq_num = htonl(36363636);
00192                 tcp_conn->seq_num = htonl(ntohl(tcp_conn->seq_num) + 1);
00193                 packet->tcp_ack = 1;
00194                 packet->tcp_chk = 0;
00195                 packet->tcp_chk = tcp_checksum(packet, len, ip_dst, ip_src);
00196                 send_ip_packet(ip_src, packet, len, 255, IPPROTO_TCP);
00197 
00198                 UP(&tcp_mutex);
00199                 return;
00200         }
00201         if ( (packet->tcp_rst) && (tcp_conn!=NULL) )
00202         {
00203                 // Free the TCP connection structure            //
00204                 kfree(tcp_conn);
00205                 tcp_conn = NULL;
00206                 disconnect_sound();
00207                 kprintf("\n\rTCP connection closed!\n\r");
00208 
00209                 UP(&tcp_mutex);
00210                 return;
00211         }
00212         if ( (packet->tcp_fin) && (tcp_conn!=NULL) )
00213         {
00214                 if ( tcp_conn->state != TCP_ESTABLISHED )
00215                         return;
00216 
00217                 // FIN received!                                        //
00218                 // Close the connection                                 //
00219 
00220                 // Send ACK (seq+1) and close also our connection       //
00221                 // setting the FIN flag on                              //
00222 
00223                 // Swap source and destination ports                    //
00224                 packet->tcp_dst ^= packet->tcp_src;
00225                 packet->tcp_src ^= packet->tcp_dst;
00226                 packet->tcp_dst ^= packet->tcp_src;
00227 
00228                 packet->tcp_ack_num = htonl(ntohl(packet->tcp_seq_num) + len - packet->tcp_hdr_len*4 + 1);
00229                 packet->tcp_seq_num = tcp_conn->seq_num;
00230                 packet->tcp_hdr_len = 5;
00231                 len = sizeof(tcp_t);
00232                 packet->tcp_ack = 1;
00233                 packet->tcp_chk = 0;
00234                 packet->tcp_chk = tcp_checksum(packet, len, ip_dst, ip_src);
00235                 send_ip_packet(ip_src, packet, len, 255, IPPROTO_TCP);
00236 
00237                 // Go into the CLOSING state (wait for ACK)             //
00238                 tcp_conn->state = TCP_CLOSING;
00239 
00240                 UP(&tcp_mutex);
00241                 return;
00242         }
00243         if ( (packet->tcp_ack) && (tcp_conn->state==TCP_SYN_RCVD) )
00244         {
00245                 // Connection established!                              //
00246                 kprintf("\n\rTCP connection established!");
00247                 connect_sound();
00248                 tcp_conn->state = TCP_ESTABLISHED;
00249 
00250                 UP(&tcp_mutex);
00251                 return;
00252         }
00253 
00254         if ( tcp_conn != NULL )
00255         {
00256                 // In the other cases ack every packet                  //
00257                 if ( (tcp_conn->state == TCP_ESTABLISHED) )
00258                 {
00259                         if ( (packet->tcp_ack) && ((len - packet->tcp_hdr_len*4)==0) )
00260                         {
00261                                 // Empty packet with ack! Do not reply  //
00262                                 UP(&tcp_mutex);
00263                                 return;
00264                         }
00265 
00266                         // Swap source and destination ports            //
00267                         packet->tcp_dst ^= packet->tcp_src;
00268                         packet->tcp_src ^= packet->tcp_dst;
00269                         packet->tcp_dst ^= packet->tcp_src;
00270 
00271                         // Send an echo packet to acknowledge           //
00272                         packet->tcp_ack_num = htonl(ntohl(packet->tcp_seq_num) + len - packet->tcp_hdr_len*4);
00273                         // tcp_conn->seq_num = htonl(ntohl(tcp_conn->seq_num) + 1);
00274                         packet->tcp_seq_num = tcp_conn->seq_num;
00275                         tcp_conn->seq_num = htonl(ntohl(tcp_conn->seq_num) + len - packet->tcp_hdr_len*4);
00276                         // packet->tcp_hdr_len = 5;
00277                         // len = sizeof(tcp_t);
00278                         packet->tcp_ack = 1;
00279                         packet->tcp_chk = 0;
00280                         packet->tcp_chk = tcp_checksum(packet, len, ip_dst, ip_src);
00281                         send_ip_packet(ip_src, packet, len, 255, IPPROTO_TCP);
00282 
00283                         UP(&tcp_mutex);
00284                         return;
00285                 }
00286                 if ( (tcp_conn->state == TCP_CLOSING) )
00287                 {
00288                         // ACK received!                                //
00289                         // Free the TCP connection structure            //
00290                         kfree(tcp_conn);
00291                         tcp_conn = NULL;
00292                         disconnect_sound();
00293                         kprintf("\n\rTCP connection closed!\n\r");
00294 
00295                         UP(&tcp_mutex);
00296                         return;
00297                 }
00298         }
00299 
00300         UP(&tcp_mutex);
00301 }
00302 
00303 int tcp_module_init()
00304 {
00305         INIT_MUTEX(&tcp_mutex);
00306         return(0);
00307 }
00308 
00309 int tcp_module_close()
00310 {
00311         return(0);
00312 }
00313 

Generated on Fri Feb 20 15:32:16 2004 for Minirighi by doxygen1.2.18