Main Page | Class List | File List | Class Members | File Members

tcp.c

Go to the documentation of this file.
00001 /* TCP handling code.
00002  *
00003  *      $Id: tcp.c,v 1.23 2002/05/16 16:15:11 joel Exp $
00004  */
00005 
00006 #include <stdio.h>
00007 #include <string.h>
00008 #include <netinet/in.h>
00009 #include <linux/ip.h>
00010 #include <linux/tcp.h>
00011 #include <sys/socket.h>
00012 #include <netinet/in.h>
00013 #include <arpa/inet.h>
00014 #include <pthread.h>
00015 #include <assert.h>
00016 
00017 #include "misc.h"
00018 #include "tcpproxy.h"
00019 #include "scheduler.h"
00020 #include "tcptimer.h"
00021 #include "tcp.h"
00022 
00023 /*
00024  * Global Variables
00025  */
00026 static unsigned win_clamp_size = TCP_WIN_CLAMP_SIZE;  /* Clamped window size.  */
00027 static Ttcp_cb tcp_tab[TCP_MAX_CONN];      /* Initialised to zero by init_tcp. */
00028 static pthread_mutex_t tcp_tab_mut;        /* Mutex for the tcp table.         */
00029 
00030 /*----------------------------------------------------------------------
00031  * init_tcp -  initialises all tcp data structures
00032  *----------------------------------------------------------------------
00033  */
00034 void init_tcp()
00035 {
00036     int i;
00037     //DPRINT("init_tcp: entered.\n");
00038 
00039     memset(tcp_tab, 0, sizeof(Ttcp_cb)*TCP_MAX_CONN);
00040     pthread_mutex_init(&tcp_tab_mut, NULL);
00041     for(i=0; i<TCP_MAX_CONN; i++) {
00042         tcp_tab[i].state = TCPS_FREE;
00043         tcp_tab[i].out_queue = -1;
00044         pthread_mutex_init(&tcp_tab[i].mut, NULL);
00045     }
00046 }
00047 
00048 /*----------------------------------------------------------------------
00049  * cleanup_tcp -  cleans up after tcp
00050  *----------------------------------------------------------------------
00051  */
00052 void cleanup_tcp()
00053 {
00054   //DPRINT("cleanup_tcp: entered.\n");
00055 }
00056 
00057 /*----------------------------------------------------------------------
00058  * seq_cmp -  compares two sequence values; because of integer overflow,
00059  *            as long as the values differ by no more than one-half the
00060  *            largest sequence space value, the compare will work.
00061  *            a - b = -ve : a is before b
00062  *            a - b = 0   : a equals b
00063  *            a - b = +ve : a is after b
00064  *----------------------------------------------------------------------
00065  */
00066 inline int seq_cmp(unsigned a, unsigned b)
00067 {
00068     return (int)(a - b);
00069 }
00070 
00071 /*----------------------------------------------------------------------
00072  * allow_conn -  returns true if a tcp connection is allowed, false
00073  *               otherwise.
00074  *----------------------------------------------------------------------
00075  */
00076 inline int allow_conn(Tpacket_data *pd)
00077 {
00078     if(ntohs(pd->trans.tcp->dest) == 5009)
00079         return 0;
00080     return 1;
00081 }
00082 
00083 /*----------------------------------------------------------------------
00084  * get_queue_weight -  returns the weight to be allocated to a queue,
00085  *                     based on the cid.
00086  *----------------------------------------------------------------------
00087  */
00088 unsigned get_queue_weight(Ttcp_cid *cid)
00089 {
00090     if(ntohs(cid->sport) == 5005)
00091         return QUEUE_WEIGHT_HIGH;
00092     else
00093         return QUEUE_WEIGHT_NORMAL;
00094 }
00095 
00096 /*----------------------------------------------------------------------
00097  * alloc_tcp_cb -  allocates a control block for a tcp connection.
00098  *                 value of cid must be such that saddr is that of the
00099  *                 host on proxied link (e.g. the mobile host).
00100  *                 ASSUMES tcp_tab_mut HELD
00101  *----------------------------------------------------------------------
00102  */
00103 Ttcp_cb *alloc_tcp_cb(Tpacket_data *pd, Ttcp_cid *cid)
00104 {
00105     Ttcp_cb *cb;
00106     int queue_num;
00107     unsigned weight;
00108     int i;
00109 
00110     for(i=0; i<TCP_MAX_CONN; i++)
00111         if(tcp_tab[i].state == TCPS_FREE)
00112             break;
00113 
00114     if(i < TCP_MAX_CONN) {
00115         weight = get_queue_weight(cid);
00116         queue_num = alloc_tcp_queue(weight);
00117         if(queue_num >= 0) {
00118             cb = &tcp_tab[i];
00119             memcpy(&(cb->cid), cid, sizeof(Ttcp_cid));
00120             cb->state = TCPS_NEW;
00121             cb->init = 0;
00122             cb->out_queue = queue_num;
00123             DPRINT("tcb_cb_alloc: allocated new connection block.\n");      
00124         } else {
00125             cb = NULL;
00126             DPRINT("alloc_tcp_cb: no free tcp output queues.\n");
00127         }
00128     } else {
00129         cb = NULL;
00130         DPRINT("alloc_tcp_cb: no free control blocks.\n");
00131     }
00132 
00133     return cb;
00134 }
00135 
00136 /*----------------------------------------------------------------------
00137  * dealloc_tcp_cb -  deallocates a control block for a tcp connection
00138  *                   ASSUMES cb->mut HELD
00139  *----------------------------------------------------------------------
00140  */
00141 int dealloc_tcp_cb(Ttcp_cb *cb)
00142 {
00143     DPRINT("dealloc_tcp_cb: entered.\n");
00144     close_tcp_queue(cb->out_queue);
00145     cb->state = TCPS_FREE;    
00146     return 0;
00147 }
00148 
00149 inline int valid_ack(Ttcp_cb *cb, Tpacket_data *pd)
00150 {
00151     if(pd->dir == PACKET_DIR_IN) {
00152         return (ntohl(pd->trans.tcp->ack_seq) == cb->mh_seq);
00153     } else {
00154         return (ntohl(pd->trans.tcp->ack_seq) == cb->fh_seq);
00155     }
00156 }
00157 
00158 /*----------------------------------------------------------------------
00159  * tcp_chksum - verifies checksum for tcp
00160  *              returns zero for valid checksum, non-zero otherwise.
00161  *----------------------------------------------------------------------
00162  */
00163 unsigned short tcp_chksum(struct iphdr *ip)
00164 {
00165     unsigned short *ptr;
00166     unsigned short len, words;
00167     unsigned long chksum = 0;
00168     int i;
00169 
00170     /* TCP pseudo header format, which is included in checksum:
00171      *
00172      * +--------+--------+--------+--------+
00173      * |           Source Address          |
00174      * +--------+--------+--------+--------+
00175      * |         Destination Address       |
00176      * +--------+--------+--------+--------+
00177      * |  zero  | Proto  |    TCP Length   |
00178      * +--------+--------+--------+--------+
00179      */
00180                         
00181     /* Add src and dst addresses to chksum. */
00182     ptr = (unsigned short*) &(ip->saddr);
00183     for(i=0; i<4; i++)
00184         chksum += *ptr++;
00185 
00186     ptr = ((unsigned short*)ip) + ip->ihl*2;  /* Set ptr to start of tcp hdr. */
00187     len = ntohs(ip->tot_len) - ip->ihl*4;  /* Calculate ip data len. */
00188     chksum += htons(TCP_PROTO) + htons(len);  /* Add protocol type and TCP segment length in. */    
00189 
00190     words = len >> 1;  /* Convert len to length in 16 bit words. */
00191 
00192     for(i=0; i<words; i++)  /* Add words in TCP segment in. */
00193         chksum += *ptr++;
00194 
00195     if(len % 2)  /* If len is odd, pad final byte and add it in. */
00196         chksum += htons((unsigned short) (*((char *)ptr) << 8));
00197 
00198     chksum = (chksum >> 16) + (chksum & 0xffff);  /* Add carry. */
00199     chksum += (chksum >> 16);                     /* And again. */
00200     chksum = ~chksum & 0xffff;  /* Take ones complement and mask off high bits. */
00201 
00202     return (short) chksum;
00203 }
00204 
00205 /*----------------------------------------------------------------------
00206  * send_tcp_rst -  sends a TCP reset packet;
00207  *                 the old for the RST.
00208  *----------------------------------------------------------------------
00209  */
00210 int send_tcp_rst (Tpacket_data *pd)
00211 {
00212     struct iphdr *ip_out, *ip_in = pd->ip;
00213     struct tcphdr *tcp_out, *tcp_in = pd->trans.tcp;
00214     int pkt_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
00215     int data_len;
00216 
00217     DPRINT("send_tcp_rst: entered.\n");
00218 
00219     if(tcp_in->rst) {
00220         DPRINT("send_tcp_rst: not sending RST in response to RST.\n");
00221         return 0;  /* Don't send RST in response to RST. */
00222     }
00223     ip_out = (struct iphdr *) xmalloc(pkt_len);
00224     tcp_out = (struct tcphdr*) (ip_out + 1);
00225     
00226     /* Set fields in IP header. */
00227     ip_out->version = IP_VERSION;
00228     ip_out->ihl = sizeof(struct iphdr)/4;
00229     ip_out->tos = 0;
00230     ip_out->tot_len = htons(pkt_len);
00231     ip_out->id = 0;
00232     ip_out->frag_off = htons(0x40<<8);  // Don't fragment bit set, offset zero.
00233     ip_out->ttl = IP_START_TTL;
00234     ip_out->protocol = TCP_PROTO;
00235     ip_out->saddr = ip_in->daddr;
00236     ip_out->daddr = ip_in->saddr;
00237 
00238     /* Set fields in TCP header. */
00239     tcp_out->source = tcp_in->dest;
00240     tcp_out->dest = tcp_in->source;
00241     if(tcp_in->ack) {
00242         tcp_out->seq = tcp_in->ack_seq;
00243         tcp_flag_word(tcp_out) = TCP_FLAG_RST;
00244     } else {
00245         tcp_out->seq = 0;
00246         tcp_flag_word(tcp_out) = TCP_FLAG_RST | TCP_FLAG_ACK;
00247     }
00248     data_len = ntohs(ip_in->tot_len) - ip_in->ihl*4 - tcp_in->doff*4;
00249     if(tcp_in->syn)
00250         data_len++;  /* Syn counts as one byte in the stream. */
00251     if(tcp_in->fin)
00252         data_len++;  /* Fin counts as one byte in the stream. */
00253     tcp_out->ack_seq = htonl(ntohl(tcp_in->seq) + data_len);
00254     tcp_out->doff = sizeof(struct tcphdr)/4;
00255     tcp_out->res1 = 0;
00256     tcp_out->window = tcp_out->urg_ptr = tcp_out->check = 0;
00257     tcp_out->check = tcp_chksum(ip_out);
00258 
00259     /* Free old payload and put new paylod into packet data structure. */
00260     xfree(pd->payload);
00261     pd->payload = (char *)ip_out;
00262     pd->ip = ip_out;
00263     pd->trans.tcp = tcp_out;
00264     
00265     /* Set length of packet in ipq_packet_msg_t struct within pd. */
00266     pd->ipq_pm.data_len = pkt_len;
00267 
00268     /* Reverse packet direction. */
00269     if(pd->dir == PACKET_DIR_IN)
00270         pd->dir = PACKET_DIR_OUT;
00271     else
00272         pd->dir = PACKET_DIR_IN;
00273         
00274     /* Queued as hipri because there is no TCP connection, thus no queue. */
00275     return queue_hipri(pd);
00276 }
00277 
00278 /*----------------------------------------------------------------------
00279  * clamp_tcp_win -  clamps tcp window if it is too high;
00280  *                  modifies the packet passed to it.
00281  *----------------------------------------------------------------------
00282  */
00283 int clamp_tcp_win (Tpacket_data *pd)
00284 {    
00285     struct tcphdr *tcp = pd->trans.tcp;    
00286     unsigned window = ntohs(tcp->window);
00287     if(window > win_clamp_size)
00288     {
00289         tcp->window = htons(win_clamp_size);
00290         tcp->check = 0;
00291         tcp->check = tcp_chksum(pd->ip);
00292         //DPRINT("clamp_tcp_win: window clamped: %d -> %d\n", window, win_clamp_size);
00293         return 1;
00294     } else {
00295         //DPRINT("clamp_tcp_win: window ok: %d\n", window);
00296         return 0;
00297     }
00298 }
00299 
00300 /*----------------------------------------------------------------------
00301  * tcp_data_size -  returns the size of the tcp data in a packet, which
00302  *                  includes syn and fin flags (one byte each).
00303  *----------------------------------------------------------------------
00304  */
00305 inline int tcp_data_size(Tpacket_data *pd)
00306 {
00307     struct tcphdr *tcp = pd->trans.tcp;
00308     int size = 0;
00309 
00310     size += tcp->syn ? 1 : 0;
00311     size += tcp->fin ? 1 : 0;
00312     size += pd->ipq_pm.data_len - pd->ip->ihl*4 - tcp->doff*4;
00313 
00314     return size;
00315 }
00316 
00317 /*----------------------------------------------------------------------
00318  * tcps_err
00319  *----------------------------------------------------------------------
00320  */
00321 int tcps_err (Ttcp_cb *cb, Tpacket_data *pd)
00322 {
00323     EPRINT("tcps_err: entered.\n");
00324     assert(UNREACHABLE);
00325 }
00326 
00327 /*----------------------------------------------------------------------
00328  * tcps_new
00329  *----------------------------------------------------------------------
00330  */
00331 int tcps_new (Ttcp_cb *cb, Tpacket_data *pd) 
00332 {
00333     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00334         cb->state = TCPS_SYN_RECV;
00335         DPRINT("tcps_new: state new->syn_recv.\n");
00336 
00337     } else {                        /* Outgoing packet. */
00338         cb->state = TCPS_SYN_SENT;
00339         add_timer(TCP_TWO_MSL, tcp_timeout, cb);
00340         DPRINT("tcps_new: state new->syn_sent.\n");
00341     }
00342     return 0;
00343 }
00344 
00345 /*----------------------------------------------------------------------
00346  * tcps_syn_sent
00347  *----------------------------------------------------------------------
00348  */
00349 int tcps_syn_sent (Ttcp_cb *cb, Tpacket_data *pd)
00350 {
00351     struct tcphdr *tcp = pd->trans.tcp;
00352 
00353     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00354         if(tcp->syn) {
00355             clear_timer(tcp_timeout, cb);
00356             if(tcp->ack) {
00357                 if(valid_ack(cb, pd)) {
00358                     cb->state = TCPS_ESTABLISHED;
00359                     DPRINT("tcps_syn_sent: syn-ack, state syn_sent->established.\n");
00360                 } else {
00361                     DPRINT("tcps_syn_sent: bad ack number.\n");
00362                 }
00363             } else {
00364                 cb->state = TCPS_SYN_RECV;
00365                 DPRINT("tcps_syn_sent: syn, state syn_sent->syn_recv.\n");
00366             }
00367         } else {
00368             DPRINT("tcps_syn_sent: no syn bit, invalid packet.\n");
00369         }
00370 
00371     } else {                        /* Outgoing packet. */
00372         DPRINT("tcps_syn_sent: state syn_sent.\n");
00373     }
00374     return 0;
00375 }
00376 
00377 /*----------------------------------------------------------------------
00378  * tcps_syn_recv
00379  *----------------------------------------------------------------------
00380  */
00381 int tcps_syn_recv (Ttcp_cb *cb, Tpacket_data *pd)
00382 {
00383     struct tcphdr *tcp = pd->trans.tcp;
00384 
00385     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00386         if(tcp->ack) {
00387             if(valid_ack(cb, pd)) {
00388                 cb->state = TCPS_ESTABLISHED;
00389                 DPRINT("tcps_syn_recv: ack, state syn_recv->established.\n");
00390             } else {
00391                 DPRINT("tcps_syn_recv: bad ack number.\n");
00392             }
00393         } else {
00394             DPRINT("tcps_syn_recv: state syn_recv.\n");
00395         }
00396 
00397     } else {                        /* Outgoing packet. */
00398         if(tcp->fin) {
00399             cb->state = TCPS_FIN_WAIT1;
00400             DPRINT("tcps_syn_recv: fin, state syn_recv->fin_wait1.\n");
00401         } else {
00402             DPRINT("tcps_syn_recv: state syn_recv.\n");
00403         }
00404     }
00405     return 0;
00406 }
00407 
00408 /*----------------------------------------------------------------------
00409  * tcps_established
00410  *----------------------------------------------------------------------
00411  */
00412 int tcps_established (Ttcp_cb *cb, Tpacket_data *pd)
00413 {
00414     struct tcphdr *tcp = pd->trans.tcp;
00415 
00416     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00417         if(tcp->fin) {
00418             cb->state = TCPS_CLOSE_WAIT;
00419             DPRINT("tcps_established: fin, state established->close_wait.\n");
00420         } else {
00421             DPRINT("tcps_established: normal traffic.\n");
00422         } 
00423     } else {                        /* Outgoing packet. */
00424         if(tcp->fin) {
00425             cb->state = TCPS_FIN_WAIT1;
00426             DPRINT("tcps_established: fin, state established->fin_wait1.\n");
00427         } else {
00428             DPRINT("tcps_established: normal traffic.\n");
00429         }
00430     }
00431     return 0;
00432 }
00433 
00434 /*----------------------------------------------------------------------
00435  * tcps_fin_wait1
00436  *----------------------------------------------------------------------
00437  */
00438 int tcps_fin_wait1 (Ttcp_cb *cb, Tpacket_data *pd)
00439 {
00440     struct tcphdr *tcp = pd->trans.tcp;
00441 
00442     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00443         if(tcp->fin) {
00444             if(tcp->ack) {
00445                 if(valid_ack(cb, pd)) {
00446                     cb->state = TCPS_TIME_WAIT;
00447                     add_timer(TCP_TWO_MSL, tcp_timeout, cb);
00448                     DPRINT("tcps_fin_wait1: fin-ack, state fin_wait1->time_wait.\n");
00449                 } else {
00450                     cb->state = TCPS_CLOSING;
00451                     DPRINT("tcps_fin_wait1: fin, state fin_wait1->closing.\n");
00452                 }
00453             } else {
00454                 DPRINT("tcps_fin_wait1: fin without ack bit set, invalid packet.\n");
00455             }
00456         } else if(tcp->ack) {
00457             if(valid_ack(cb, pd))
00458             {
00459                 cb->state = TCPS_FIN_WAIT2;
00460                 DPRINT("tcps_fin_wait1: ack, state fin_wait1->fin_wait2.\n");
00461             } else {
00462                 DPRINT("tcps_fin_wait1: state fin_wait1.\n");
00463             }
00464         } else {
00465             DPRINT("tcps_fin_wait1: no ack bit set, bad packet.\n");
00466         }
00467         
00468     } else {                        /* Outgoing packet. */
00469         DPRINT("tcps_fin_wait1: state fin_wait1.\n");
00470     }
00471     return 0;
00472 }
00473 
00474 /*----------------------------------------------------------------------
00475  * tcps_fin_wait2
00476  *----------------------------------------------------------------------
00477  */
00478 int tcps_fin_wait2 (Ttcp_cb *cb, Tpacket_data *pd)
00479 {
00480     struct tcphdr *tcp = pd->trans.tcp;
00481 
00482     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00483         if(tcp->fin) {
00484             cb->state = TCPS_TIME_WAIT;
00485             add_timer(TCP_TWO_MSL, tcp_timeout, cb);
00486             DPRINT("tcps_fin_wait2: fin, state fin_wait2->time_wait.\n");
00487         } else {
00488             DPRINT("tcps_fin_wait2: state fin_wait2.\n");
00489         }
00490         
00491     } else {                        /* Outgoing packet. */
00492         DPRINT("tcps_fin_wait2: state fin_wait2.\n");
00493     }
00494     return 0;
00495 }
00496 
00497 /*----------------------------------------------------------------------
00498  * tcps_time_wait
00499  *----------------------------------------------------------------------
00500  */
00501 int tcps_time_wait (Ttcp_cb *cb, Tpacket_data *pd)
00502 {
00503     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00504         DPRINT("tcps_time_wait: state time_wait.\n");
00505 
00506     } else {                        /* Outgoing packet. */
00507         DPRINT("tcps_time_wait: state time_wait.\n");
00508     }
00509     return 0;
00510 }
00511 
00512 /*----------------------------------------------------------------------
00513  * tcps_closed
00514  *----------------------------------------------------------------------
00515  */
00516 int tcps_closed (Ttcp_cb *cb, Tpacket_data *pd)
00517 {
00518     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00519         EPRINT("tcps_closed: shouldn't ever get here.\n");
00520         assert(UNREACHABLE);
00521     } else {                        /* Outgoing packet. */
00522         EPRINT("tcps_closed: shouldn't ever get here.\n");
00523         assert(UNREACHABLE);
00524     }
00525     return 0;
00526 }
00527 
00528 /*----------------------------------------------------------------------
00529  * tcps_close_wait
00530  *----------------------------------------------------------------------
00531  */
00532 int tcps_close_wait (Ttcp_cb *cb, Tpacket_data *pd)
00533 {
00534     struct tcphdr *tcp = pd->trans.tcp;
00535 
00536     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00537         DPRINT("tcps_close_wait: state close_wait.\n");
00538 
00539     } else {                        /* Outgoing packet. */
00540         if(tcp->fin) {
00541             if(tcp->ack) {
00542                 if(valid_ack(cb, pd)) {  /* MH FIN with ACK for the FIN that FH sent. */
00543                     cb->state = TCPS_LAST_ACK;
00544                     add_timer(TCP_TWO_MSL, tcp_timeout, cb);
00545                     DPRINT("tcp_close_wait: fin, state close_wait->last_ack.\n");
00546                 } else {  /* MH FIN without ACK for FIN from FH (FINs sent at same time). */
00547                     cb->state = TCPS_CLOSING;
00548                     DPRINT("tcp_close_wait: fin, state close_wait->closing "
00549                            "(wasn't actually in close_wait).\n");
00550                 }
00551             } else {
00552                 DPRINT("tcps_close_wait: fin without ack bit set, invalid packet.\n");
00553             }
00554         } else {
00555             DPRINT("tcps_close_wait: state close_wait.\n");
00556         }
00557     }
00558     return 0;
00559 }
00560 
00561 /*----------------------------------------------------------------------
00562  * tcps_last_ack
00563  *----------------------------------------------------------------------
00564  */
00565 int tcps_last_ack (Ttcp_cb *cb, Tpacket_data *pd)
00566 {
00567     struct tcphdr *tcp = pd->trans.tcp;
00568 
00569     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00570         if(tcp->ack) {
00571             if(valid_ack(cb, pd)) {
00572                 cb->state = TCPS_CLOSED;
00573                 DPRINT("tcps_last_ack: ack, state last_ack->closed.\n");
00574             } else {
00575                 DPRINT("tcps_last_ack: bad ack number.\n");
00576             }
00577         } else {
00578             DPRINT("tcps_last_ack: no ack bit set, bad packet.\n");
00579         }
00580         
00581     } else {                        /* Outgoing packet. */
00582         DPRINT("tcps_last_ack: state last_ack.\n");
00583     }
00584     return 0;
00585 }
00586 
00587 /*----------------------------------------------------------------------
00588  * tcps_closing
00589  *----------------------------------------------------------------------
00590  */
00591 int tcps_closing (Ttcp_cb *cb, Tpacket_data *pd)
00592 {
00593     struct tcphdr *tcp = pd->trans.tcp;
00594 
00595     if(pd->dir == PACKET_DIR_IN) {  /* Incoming packet. */
00596         if(tcp->ack) {
00597             if(valid_ack(cb, pd)) {
00598                 cb->state = TCPS_TIME_WAIT;
00599                 add_timer(TCP_TWO_MSL, tcp_timeout, cb);
00600                 DPRINT("tcps_closing: ack, state closing->time_wait.\n");
00601             } else {
00602                 DPRINT("tcps_closing: bad ack number.\n");
00603             }               
00604         } else {
00605             DPRINT("tcps_closing: state closing.\n");
00606         }
00607 
00608     } else {                        /* Outgoing packet. */
00609         DPRINT("tcps_closing: state closing.\n");
00610     }
00611     return 0;
00612 }
00613 
00614 /* Array holding pointers to tcp state routines. */
00615 int (*tcp_switch[TCPS_MAX_STATES])() = {
00616     tcps_err,           /* TCPS_FREE        */
00617     tcps_new,           /* TCPS_NEW         */
00618     tcps_syn_sent,      /* TCPS SYN_SENT    */
00619     tcps_syn_recv,      /* TCPS_SYN_RECV    */
00620     tcps_established,   /* TCPS_ESTABLISHED */
00621     tcps_fin_wait1,     /* TCPS_FIN_WAIT1   */
00622     tcps_fin_wait2,     /* TCPS_FIN_WAIT2   */
00623     tcps_time_wait,     /* TCPS_TIME_WAIT   */
00624     tcps_closed,        /* TCPS_CLOSED       */
00625     tcps_close_wait,    /* TCPS_CLOSE_WAIT  */
00626     tcps_last_ack,      /* TCPS_LAST_ACK    */
00627     tcps_closing        /* TCPS_CLOSING     */
00628 };
00629 
00630 /*----------------------------------------------------------------------
00631  * tcp_timeout -  called by tcp_timer when a tcp state times out
00632  *----------------------------------------------------------------------
00633  */
00634 void tcp_timeout(void *ptr)
00635 {
00636     Ttcp_cb *cb = (Ttcp_cb *)ptr;
00637 
00638     assert(cb != NULL);
00639 
00640     mutex_lock("tcp_timeout", &cb->mut);
00641     switch(cb->state)
00642     {
00643     case TCPS_SYN_SENT:
00644         DPRINT("tcp_timeout: state syn_sent.\n");
00645         break;
00646     case TCPS_LAST_ACK:
00647         DPRINT("tcp_timeout: state last_ack.\n");
00648         break;
00649     case TCPS_TIME_WAIT:
00650         DPRINT("tcp_timeout: state time_wait.\n");
00651         break;
00652     default:
00653         EPRINT("tcp_timeout: called with tcp in a state which does not have a timeout: %d\n", 
00654                cb->state);
00655         mutex_unlock("tcp_timeout", &cb->mut);
00656         return;
00657         break;
00658     }
00659     cb->state = TCPS_CLOSED;
00660     dealloc_tcp_cb(cb);
00661     mutex_unlock("tcp_timeout", &cb->mut);    
00662 }
00663 
00664 /*----------------------------------------------------------------------
00665  * handle_tcp -  deals with TCP packets from the main packet handler
00666  *----------------------------------------------------------------------
00667  */
00668 int handle_tcp(Tpacket_data *pd)
00669 {
00670     struct iphdr *ip = pd->ip;
00671     struct tcphdr *tcp;
00672     Ttcp_cid cid;  /* Connection id. */
00673     Ttcp_cid rcid; /* Connection id, with src and dst reversed. */
00674     Ttcp_cb *cb;
00675     int i;
00676 
00677     assert(pd != NULL);
00678 
00679     /* Check if there is enough data for a valid tcp header. */
00680     if((ip->ihl * 4 + 20) >  pd->ipq_pm.data_len) {
00681         DPRINT("handle_tcp: malformed TCP packet: not enough data.\n");
00682         dealloc_packet_data(pd);
00683         return 1;
00684     }
00685 
00686     tcp = pd->trans.tcp;
00687 
00688     if(tcp_chksum(pd->ip)) {
00689         DPRINT("handle_tcp: bad TCP checksum: %u\n", ntohs(tcp->check));
00690         dealloc_packet_data(pd);
00691         return 1;
00692     }
00693 
00694     DPRINT("tcp sport: %u, dport: %u, seq: %u, ack: %u, hlen: %u, flags: %c%c%c%c%c%c\n",
00695            ntohs(tcp->source), ntohs(tcp->dest), ntohl(tcp->seq), ntohl(tcp->ack_seq),
00696            tcp->doff,
00697            (tcp->urg ?'U':'.'), (tcp->ack ?'A':'.'), (tcp->psh ?'P':'.'),
00698            (tcp->rst ?'R':'.'), (tcp->syn ?'S':'.'), (tcp->fin ?'F':'.'));
00699     
00700     cid.saddr = ip->saddr;
00701     cid.daddr = ip->daddr;
00702     cid.sport = tcp->source;
00703     cid.dport = tcp->dest;
00704     rcid.saddr = ip->daddr;
00705     rcid.daddr = ip->saddr;
00706     rcid.sport = tcp->dest;
00707     rcid.dport = tcp->source;
00708     
00709     mutex_lock("handle_tcp", &tcp_tab_mut);
00710 
00711     for(cb=&tcp_tab[0], i=0; i<TCP_MAX_CONN; i++, cb++) {
00712         if(cb->state != TCPS_FREE) {
00713             if(memcmp(&(cb->cid), &cid, sizeof(Ttcp_cid)) == 0 ||
00714                memcmp(&(cb->cid), &rcid, sizeof(Ttcp_cid)) == 0)
00715                 break;
00716         }
00717     }
00718 
00719     if(i >= TCP_MAX_CONN) {  /* Connection doesn't already exists. */
00720         if(tcp->syn & !tcp->ack) {  /* Connect */
00721             if(allow_conn(pd)) {  /* Connection allowed. */
00722                 Ttcp_cid *ncid; /* 'Normalised' cid. */
00723 
00724                 /* Determine direction of packet, and call add_stream with appropriate cid,
00725                  * abiding by cid rule for tcp_stream_node (see struct def).
00726                  */
00727                 if(pd->dir == PACKET_DIR_IN)
00728                     ncid = &rcid;  /* Packet to mobile host. */
00729                 else
00730                     ncid = &cid;  /* Packet from mobile host. */
00731 
00732                 cb = alloc_tcp_cb(pd, ncid);                
00733 
00734                 if(cb == NULL) {
00735                     dealloc_packet_data(pd);
00736                     mutex_unlock("handle_tcp", &tcp_tab_mut);
00737                     return -1;
00738                 }
00739             } else {  /* Connection denied. */
00740                 mutex_unlock("handle_tcp", &tcp_tab_mut);
00741                 DPRINT("handle_tcp: connection denied: %s:%u > ",
00742                        inet_ntoa(*(struct in_addr*)&(cid.saddr)), ntohs(cid.sport));
00743                 DPRINT("%s:%u\n",
00744                        inet_ntoa(*(struct in_addr*)&(cid.daddr)), ntohs(cid.dport));
00745                 send_tcp_rst(pd);
00746                 return 1;
00747             }
00748         } else {  /* New connection, but not initial syn. */        
00749             DPRINT("handle_tcp: new connection mid-stream.\n");
00750             mutex_unlock("handle_tcp", &tcp_tab_mut);
00751             send_tcp_rst(pd);
00752             return 1;
00753         }
00754     }
00755     assert(cb != NULL);
00756 
00757     mutex_lock("handle_tcp", &cb->mut);
00758     mutex_unlock("handle_tcp", &tcp_tab_mut);
00759 
00760     /* RST packet, so clear the queue and close the connection. */
00761     if(tcp->rst) {
00762         cb->state = TCPS_CLOSED;
00763         DPRINT("handle_tcp: rst, state ->closed.\n");
00764         reset_tcp_queue(cb->out_queue);
00765         queue_hipri(pd);  /* Queue as hipri so the RST is received quickly. */
00766 
00767     } else if((tcp_switch[cb->state])(cb, pd) == 0) {  /* Call state function. */
00768         /* If packet is to be queued, first update seq and ack_seq numbers. */
00769         unsigned ack_seq = ntohl(tcp->ack_seq);
00770         unsigned seq = ntohl(tcp->seq) + tcp_data_size(pd);
00771 
00772         if(pd->dir == PACKET_DIR_IN)
00773         {
00774             if(tcp->ack) {
00775                 if((cb->init & TCP_INIT_MH_ACK) == 0) {
00776                     cb->mh_ack = ack_seq;
00777                     cb->init |= TCP_INIT_MH_ACK;
00778                     DPRINT("handle_tcp: init mh_ack=%u\n", ack_seq);
00779                 } else if(seq_cmp(ack_seq, cb->mh_ack) > 0) {
00780                     cb->mh_ack = ack_seq;
00781                 }
00782             }
00783             if((cb->init & TCP_INIT_FH_SEQ) == 0) {
00784                 cb->fh_seq = seq;
00785                 cb->init |= TCP_INIT_FH_SEQ;
00786                 DPRINT("handle_tcp: init fh_seq=%u\n", seq);        
00787             } else if(seq_cmp(seq, cb->fh_seq) > 0) {
00788                 cb->fh_seq = seq;
00789             }
00790         } else {
00791             if(tcp->ack) {
00792                 if((cb->init & TCP_INIT_FH_ACK) == 0) {
00793                     cb->fh_ack = ack_seq;
00794                     cb->init |= TCP_INIT_FH_ACK;
00795                     DPRINT("handle_tcp: init fh_ack=%d\n", ack_seq);
00796                 } else if(seq_cmp(ack_seq, cb->fh_ack) > 0) {               
00797                     cb->fh_ack = ack_seq;
00798                     /* Signal to the scheduler that an ack has arrived, with the number of
00799                      * bytes it is acking. */
00800                     mh_ack_rcvd(ack_seq, cb->out_queue);
00801                 }
00802             }
00803             if((cb->init & TCP_INIT_MH_SEQ) == 0) {
00804                 cb->mh_seq = seq;
00805                 cb->init |= TCP_INIT_MH_SEQ;
00806                 DPRINT("handle_tcp: init mh_seq=%u\n", seq);
00807             } else if(seq_cmp(seq, cb->mh_seq) > 0) {
00808                 cb->mh_seq = seq;
00809             }
00810         }
00811         clamp_tcp_win(pd);             /* Clamp advertised window size. */
00812         queue_tcp(pd, cb->out_queue);  /* Queue the packet.             */
00813     }
00814 
00815     if(cb->state == TCPS_CLOSED)  /* Deallocate cb if connection closed. */
00816     {
00817         clear_timer(tcp_timeout, cb);
00818         dealloc_tcp_cb(cb);
00819     }
00820 
00821     mutex_unlock("handle_tcp", &cb->mut);
00822    
00823     return 0;
00824 }

Generated on Sun May 14 13:36:52 2006 by  doxygen 1.4.2