tcp.c

Go to the documentation of this file.
00001 /*
00002 tcp.c
00003 
00004 Copyright 1995 Philip Homburg
00005 */
00006 
00007 #include "inet.h"
00008 #include "buf.h"
00009 #include "clock.h"
00010 #include "event.h"
00011 #include "type.h"
00012 
00013 #include "io.h"
00014 #include "ip.h"
00015 #include "sr.h"
00016 #include "assert.h"
00017 #include "rand256.h"
00018 #include "tcp.h"
00019 #include "tcp_int.h"
00020 
00021 THIS_FILE
00022 
00023 #define NOT_IMPLEMENTED 0
00024 
00025 PUBLIC tcp_port_t *tcp_port_table;
00026 PUBLIC tcp_fd_t tcp_fd_table[TCP_FD_NR];
00027 PUBLIC tcp_conn_t tcp_conn_table[TCP_CONN_NR];
00028 PUBLIC sr_cancel_t tcp_cancel_f;
00029 
00030 FORWARD void tcp_main ARGS(( tcp_port_t *port ));
00031 FORWARD int tcp_select ARGS(( int fd, unsigned operations ));
00032 FORWARD acc_t *tcp_get_data ARGS(( int fd, size_t offset,
00033         size_t count, int for_ioctl ));
00034 FORWARD int tcp_put_data ARGS(( int fd, size_t offset,
00035         acc_t *data, int for_ioctl ));
00036 FORWARD void tcp_put_pkt ARGS(( int fd, acc_t *data, size_t datalen ));
00037 FORWARD void read_ip_packets ARGS(( tcp_port_t *port ));
00038 FORWARD int tcp_setconf ARGS(( tcp_fd_t *tcp_fd ));
00039 FORWARD int tcp_setopt ARGS(( tcp_fd_t *tcp_fd ));
00040 FORWARD int tcp_connect ARGS(( tcp_fd_t *tcp_fd ));
00041 FORWARD int tcp_listen ARGS(( tcp_fd_t *tcp_fd, int do_listenq ));
00042 FORWARD int tcp_acceptto ARGS(( tcp_fd_t *tcp_fd ));
00043 FORWARD tcpport_t find_unused_port ARGS(( int fd ));
00044 FORWARD int is_unused_port ARGS(( Tcpport_t port ));
00045 FORWARD int reply_thr_put ARGS(( tcp_fd_t *tcp_fd, int reply,
00046         int for_ioctl ));
00047 FORWARD void reply_thr_get ARGS(( tcp_fd_t *tcp_fd, int reply,
00048         int for_ioctl ));
00049 FORWARD tcp_conn_t *find_conn_entry ARGS(( Tcpport_t locport,
00050         ipaddr_t locaddr, Tcpport_t remport, ipaddr_t readaddr ));
00051 FORWARD tcp_conn_t *find_empty_conn ARGS(( void ));
00052 FORWARD tcp_conn_t *find_best_conn ARGS(( ip_hdr_t *ip_hdr, 
00053         tcp_hdr_t *tcp_hdr ));
00054 FORWARD tcp_conn_t *new_conn_for_queue ARGS(( tcp_fd_t *tcp_fd ));
00055 FORWARD int maybe_listen ARGS(( ipaddr_t locaddr, Tcpport_t locport,
00056                                 ipaddr_t remaddr, Tcpport_t remport ));
00057 FORWARD int tcp_su4connect ARGS(( tcp_fd_t *tcp_fd ));
00058 FORWARD void tcp_buffree ARGS(( int priority ));
00059 #ifdef BUF_CONSISTENCY_CHECK
00060 FORWARD void tcp_bufcheck ARGS(( void ));
00061 #endif
00062 FORWARD void tcp_setup_conn ARGS(( tcp_port_t *tcp_port,
00063                                         tcp_conn_t *tcp_conn ));
00064 FORWARD u32_t tcp_rand32 ARGS(( void ));
00065 
00066 PUBLIC void tcp_prep()
00067 {
00068         tcp_port_table= alloc(tcp_conf_nr * sizeof(tcp_port_table[0]));
00069 }
00070 
00071 PUBLIC void tcp_init()
00072 {
00073         int i, j, k, ifno;
00074         tcp_fd_t *tcp_fd;
00075         tcp_port_t *tcp_port;
00076         tcp_conn_t *tcp_conn;
00077 
00078         assert (BUF_S >= sizeof(struct nwio_ipopt));
00079         assert (BUF_S >= sizeof(struct nwio_ipconf));
00080         assert (BUF_S >= sizeof(struct nwio_tcpconf));
00081         assert (BUF_S >= IP_MAX_HDR_SIZE + TCP_MAX_HDR_SIZE);
00082 
00083         for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++, tcp_fd++)
00084         {
00085                 tcp_fd->tf_flags= TFF_EMPTY;
00086         }
00087 
00088         for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
00089                 tcp_fd++)
00090         {
00091                 tcp_conn->tc_flags= TCF_EMPTY;
00092                 tcp_conn->tc_busy= 0;
00093         }
00094 
00095 #ifndef BUF_CONSISTENCY_CHECK
00096         bf_logon(tcp_buffree);
00097 #else
00098         bf_logon(tcp_buffree, tcp_bufcheck);
00099 #endif
00100 
00101         for (i=0, tcp_port= tcp_port_table; i<tcp_conf_nr; i++, tcp_port++)
00102         {
00103                 tcp_port->tp_ipdev= tcp_conf[i].tc_port;
00104 
00105                 tcp_port->tp_flags= TPF_EMPTY;
00106                 tcp_port->tp_state= TPS_EMPTY;
00107                 tcp_port->tp_snd_head= NULL;
00108                 tcp_port->tp_snd_tail= NULL;
00109                 ev_init(&tcp_port->tp_snd_event);
00110                 for (j= 0; j<TCP_CONN_HASH_NR; j++)
00111                 {
00112                         for (k= 0; k<4; k++)
00113                         {
00114                                 tcp_port->tp_conn_hash[j][k]=
00115                                         &tcp_conn_table[0];
00116                         }
00117                 }
00118 
00119                 ifno= ip_conf[tcp_port->tp_ipdev].ic_ifno;
00120                 sr_add_minor(if2minor(ifno, TCP_DEV_OFF),
00121                         i, tcp_open, tcp_close, tcp_read,
00122                         tcp_write, tcp_ioctl, tcp_cancel, tcp_select);
00123 
00124                 tcp_main(tcp_port);
00125         }
00126         tcp_cancel_f= tcp_cancel;
00127 }
00128 
00129 PRIVATE void tcp_main(tcp_port)
00130 tcp_port_t *tcp_port;
00131 {
00132         int result, i;
00133         tcp_conn_t *tcp_conn;
00134         tcp_fd_t *tcp_fd;
00135 
00136         switch (tcp_port->tp_state)
00137         {
00138         case TPS_EMPTY:
00139                 tcp_port->tp_state= TPS_SETPROTO;
00140                 tcp_port->tp_ipfd= ip_open(tcp_port->tp_ipdev,
00141                         tcp_port->tp_ipdev, tcp_get_data,
00142                         tcp_put_data, tcp_put_pkt, 0 /* no select_res */);
00143                 if (tcp_port->tp_ipfd < 0)
00144                 {
00145                         tcp_port->tp_state= TPS_ERROR;
00146                         DBLOCK(1, printf("%s, %d: unable to open ip port\n",
00147                                 __FILE__, __LINE__));
00148                         return;
00149                 }
00150 
00151                 result= ip_ioctl(tcp_port->tp_ipfd, NWIOSIPOPT);
00152                 if (result == NW_SUSPEND)
00153                         tcp_port->tp_flags |= TPF_SUSPEND;
00154                 if (result < 0)
00155                 {
00156                         return;
00157                 }
00158                 if (tcp_port->tp_state != TPS_GETCONF)
00159                         return;
00160                 /* drops through */
00161         case TPS_GETCONF:
00162                 tcp_port->tp_flags &= ~TPF_SUSPEND;
00163 
00164                 result= ip_ioctl(tcp_port->tp_ipfd, NWIOGIPCONF);
00165                 if (result == NW_SUSPEND)
00166                         tcp_port->tp_flags |= TPF_SUSPEND;
00167                 if (result < 0)
00168                 {
00169                         return;
00170                 }
00171                 if (tcp_port->tp_state != TPS_MAIN)
00172                         return;
00173                 /* drops through */
00174         case TPS_MAIN:
00175                 tcp_port->tp_flags &= ~TPF_SUSPEND;
00176                 tcp_port->tp_pack= 0;
00177 
00178                 tcp_conn= &tcp_conn_table[tcp_port->tp_ipdev];
00179                 tcp_conn->tc_flags= TCF_INUSE;
00180                 assert(!tcp_conn->tc_busy);
00181                 tcp_conn->tc_locport= 0;
00182                 tcp_conn->tc_locaddr= tcp_port->tp_ipaddr;
00183                 tcp_conn->tc_remport= 0;
00184                 tcp_conn->tc_remaddr= 0;
00185                 tcp_conn->tc_state= TCS_CLOSED;
00186                 tcp_conn->tc_fd= 0;
00187                 tcp_conn->tc_connInprogress= 0;
00188                 tcp_conn->tc_orglisten= FALSE;
00189                 tcp_conn->tc_senddis= 0;
00190                 tcp_conn->tc_ISS= 0;
00191                 tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
00192                 tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
00193                 tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS;
00194                 tcp_conn->tc_SND_UP= tcp_conn->tc_ISS;
00195                 tcp_conn->tc_IRS= 0;
00196                 tcp_conn->tc_RCV_LO= tcp_conn->tc_IRS;
00197                 tcp_conn->tc_RCV_NXT= tcp_conn->tc_IRS;
00198                 tcp_conn->tc_RCV_HI= tcp_conn->tc_IRS;
00199                 tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS;
00200                 tcp_conn->tc_port= tcp_port;
00201                 tcp_conn->tc_rcvd_data= NULL;
00202                 tcp_conn->tc_adv_data= NULL;
00203                 tcp_conn->tc_send_data= 0;
00204                 tcp_conn->tc_remipopt= NULL;
00205                 tcp_conn->tc_tcpopt= NULL;
00206                 tcp_conn->tc_frag2send= 0;
00207                 tcp_conn->tc_tos= TCP_DEF_TOS;
00208                 tcp_conn->tc_ttl= IP_MAX_TTL;
00209                 tcp_conn->tc_rcv_wnd= TCP_MAX_RCV_WND_SIZE;
00210                 tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
00211                 tcp_conn->tc_stt= 0;
00212                 tcp_conn->tc_0wnd_to= 0;
00213                 tcp_conn->tc_artt= TCP_DEF_RTT*TCP_RTT_SCALE;
00214                 tcp_conn->tc_drtt= 0;
00215                 tcp_conn->tc_rtt= TCP_DEF_RTT;
00216                 tcp_conn->tc_max_mtu= tcp_port->tp_mtu;
00217                 tcp_conn->tc_mtu= tcp_conn->tc_max_mtu;
00218                 tcp_conn->tc_mtutim= 0;
00219                 tcp_conn->tc_error= NW_OK;
00220                 tcp_conn->tc_snd_wnd= TCP_MAX_SND_WND_SIZE;
00221                 tcp_conn->tc_snd_cinc=
00222                         (long)TCP_DEF_MSS*TCP_DEF_MSS/TCP_MAX_SND_WND_SIZE+1;
00223 
00224                 tcp_conn->tc_rt_time= 0;
00225                 tcp_conn->tc_rt_seq= 0;
00226                 tcp_conn->tc_rt_threshold= tcp_conn->tc_ISS;
00227 
00228                 for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++,
00229                         tcp_fd++)
00230                 {
00231                         if (!(tcp_fd->tf_flags & TFF_INUSE))
00232                                 continue;
00233                         if (tcp_fd->tf_port != tcp_port)
00234                                 continue;
00235                         if (tcp_fd->tf_flags & TFF_IOC_INIT_SP)
00236                         {
00237                                 tcp_fd->tf_flags &= ~TFF_IOC_INIT_SP;
00238                                 tcp_ioctl(i, tcp_fd->tf_ioreq);
00239                         }
00240                 }
00241                 read_ip_packets(tcp_port);
00242                 return;
00243 
00244         default:
00245                 ip_panic(( "unknown state" ));
00246                 break;
00247         }
00248 }
00249 
00250 PRIVATE int tcp_select(fd, operations)
00251 int fd;
00252 unsigned operations;
00253 {
00254         int i;
00255         unsigned resops;
00256         tcp_fd_t *tcp_fd;
00257         tcp_conn_t *tcp_conn;
00258 
00259         tcp_fd= &tcp_fd_table[fd];
00260         assert (tcp_fd->tf_flags & TFF_INUSE);
00261 
00262         resops= 0;
00263         if (tcp_fd->tf_flags & TFF_LISTENQ)
00264         {
00265                 /* Special case for LISTENQ */
00266                 if (operations & SR_SELECT_READ)
00267                 {
00268                         for (i= 0; i<TFL_LISTEN_MAX; i++)
00269                         {
00270                                 if (tcp_fd->tf_listenq[i] == NULL)
00271                                         continue;
00272                                 if (tcp_fd->tf_listenq[i]->tc_connInprogress
00273                                         == 0)
00274                                 {
00275                                         break;
00276                                 }
00277                         }
00278                         if (i >= TFL_LISTEN_MAX)
00279                                 tcp_fd->tf_flags |= TFF_SEL_READ;
00280                         else
00281                                 resops |= SR_SELECT_READ;
00282                 }
00283                 if (operations & SR_SELECT_WRITE)
00284                 {
00285                         /* We can't handles writes. Just return the error
00286                          * when the user tries to write.
00287                          */
00288                         resops |= SR_SELECT_WRITE;
00289                 }
00290                 return resops;
00291         }
00292         if (tcp_fd->tf_flags & TFF_CONNECTING)
00293         {
00294                 /* Special case for CONNECTING */
00295                 if (operations & SR_SELECT_WRITE)
00296                         tcp_fd->tf_flags |= TFF_SEL_WRITE;
00297                 return 0;
00298         }
00299         if (operations & SR_SELECT_READ)
00300         {
00301                 tcp_conn= tcp_fd->tf_conn;
00302 
00303                 if (!(tcp_fd->tf_flags & TFF_CONNECTED))
00304                 {
00305                         /* We can't handle reads until a connection has been
00306                          * established. Return the error when the user tries
00307                          * to read.
00308                          */
00309                         resops |= SR_SELECT_READ;
00310                 }
00311                 else if (tcp_conn->tc_state == TCS_CLOSED ||
00312                         tcp_sel_read(tcp_conn))
00313                 {
00314                         resops |= SR_SELECT_READ;
00315                 }
00316                 else if (!(operations & SR_SELECT_POLL))
00317                                 tcp_fd->tf_flags |= TFF_SEL_READ;
00318         }
00319         if (operations & SR_SELECT_WRITE)
00320         {
00321                 tcp_conn= tcp_fd->tf_conn;
00322                 if (!(tcp_fd->tf_flags & TFF_CONNECTED))
00323                 {
00324                         /* We can't handle writes until a connection has been
00325                          * established. Return the error when the user tries
00326                          * to write.
00327                          */
00328                         resops |= SR_SELECT_WRITE;
00329                 }
00330                 else if (tcp_conn->tc_state == TCS_CLOSED ||
00331                         tcp_conn->tc_flags & TCF_FIN_SENT ||
00332                         tcp_sel_write(tcp_conn))
00333                 {
00334                         resops |= SR_SELECT_WRITE;
00335                 }
00336                 else if (!(operations & SR_SELECT_POLL))
00337                         tcp_fd->tf_flags |= TFF_SEL_WRITE;
00338         }
00339         if (operations & SR_SELECT_EXCEPTION)
00340         {
00341                 /* Should add code for exceptions */
00342         }
00343         return resops;
00344 }
00345 
00346 PRIVATE acc_t *tcp_get_data (port, offset, count, for_ioctl)
00347 int port;
00348 size_t offset;
00349 size_t count;
00350 int for_ioctl;
00351 {
00352         tcp_port_t *tcp_port;
00353         int result;
00354 
00355         tcp_port= &tcp_port_table[port];
00356 
00357         switch (tcp_port->tp_state)
00358         {
00359         case TPS_SETPROTO:
00360                 if (!count)
00361                 {
00362                         result= (int)offset;
00363                         if (result<0)
00364                         {
00365                                 tcp_port->tp_state= TPS_ERROR;
00366                                 break;
00367                         }
00368                         tcp_port->tp_state= TPS_GETCONF;
00369                         if (tcp_port->tp_flags & TPF_SUSPEND)
00370                                 tcp_main(tcp_port);
00371                         return NW_OK;
00372                 }
00373 assert (!offset);
00374 assert (count == sizeof(struct nwio_ipopt));
00375                 {
00376                         struct nwio_ipopt *ipopt;
00377                         acc_t *acc;
00378 
00379                         acc= bf_memreq(sizeof(*ipopt));
00380                         ipopt= (struct nwio_ipopt *)ptr2acc_data(acc);
00381                         ipopt->nwio_flags= NWIO_COPY |
00382                                 NWIO_EN_LOC | NWIO_DI_BROAD |
00383                                 NWIO_REMANY | NWIO_PROTOSPEC |
00384                                 NWIO_HDR_O_ANY | NWIO_RWDATALL;
00385                         ipopt->nwio_proto= IPPROTO_TCP;
00386                         return acc;
00387                 }
00388         case TPS_MAIN:
00389                 assert(tcp_port->tp_flags & TPF_WRITE_IP);
00390                 if (!count)
00391                 {
00392                         result= (int)offset;
00393                         if (result<0)
00394                         {
00395                                 if (result == EDSTNOTRCH)
00396                                 {
00397                                         if (tcp_port->tp_snd_head)
00398                                         {
00399                                                 tcp_notreach(tcp_port->
00400                                                         tp_snd_head);
00401                                         }
00402                                 }
00403                                 else
00404                                 {
00405                                         ip_warning((
00406                                         "ip_write failed with error: %d\n", 
00407                                                                 result ));
00408                                 }
00409                         }
00410                         assert (tcp_port->tp_pack);
00411                         bf_afree (tcp_port->tp_pack);
00412                         tcp_port->tp_pack= 0;
00413 
00414                         if (tcp_port->tp_flags & TPF_WRITE_SP)
00415                         {
00416                                 tcp_port->tp_flags &= ~(TPF_WRITE_SP|
00417                                         TPF_WRITE_IP);
00418                                 if (tcp_port->tp_snd_head)
00419                                         tcp_port_write(tcp_port);
00420                         }
00421                         else
00422                                 tcp_port->tp_flags &= ~TPF_WRITE_IP;
00423                 }
00424                 else
00425                 {
00426                         return bf_cut (tcp_port->tp_pack, offset,
00427                                 count);
00428                 }
00429                 break;
00430         default:
00431                 printf("tcp_get_data(%d, 0x%x, 0x%x) called but tp_state= 0x%x\n",
00432                         port, offset, count, tcp_port->tp_state);
00433                 break;
00434         }
00435         return NW_OK;
00436 }
00437 
00438 PRIVATE int tcp_put_data (fd, offset, data, for_ioctl)
00439 int fd;
00440 size_t offset;
00441 acc_t *data;
00442 int for_ioctl;
00443 {
00444         tcp_port_t *tcp_port;
00445         int result;
00446 
00447         tcp_port= &tcp_port_table[fd];
00448 
00449         switch (tcp_port->tp_state)
00450         {
00451         case TPS_GETCONF:
00452                 if (!data)
00453                 {
00454                         result= (int)offset;
00455                         if (result<0)
00456                         {
00457                                 tcp_port->tp_state= TPS_ERROR;
00458                                 return NW_OK;
00459                         }
00460                         tcp_port->tp_state= TPS_MAIN;
00461                         if (tcp_port->tp_flags & TPF_SUSPEND)
00462                                 tcp_main(tcp_port);
00463                 }
00464                 else
00465                 {
00466                         struct nwio_ipconf *ipconf;
00467 
00468                         data= bf_packIffLess(data, sizeof(*ipconf));
00469                         ipconf= (struct nwio_ipconf *)ptr2acc_data(data);
00470 assert (ipconf->nwic_flags & NWIC_IPADDR_SET);
00471                         tcp_port->tp_ipaddr= ipconf->nwic_ipaddr;
00472                         tcp_port->tp_subnetmask= ipconf->nwic_netmask;
00473                         tcp_port->tp_mtu= ipconf->nwic_mtu;
00474                         bf_afree(data);
00475                 }
00476                 break;
00477         case TPS_MAIN:
00478                 assert(tcp_port->tp_flags & TPF_READ_IP);
00479                 if (!data)
00480                 {
00481                         result= (int)offset;
00482                         if (result<0)
00483                                 ip_panic(( "ip_read() failed" ));
00484 
00485                         if (tcp_port->tp_flags & TPF_READ_SP)
00486                         {
00487                                 tcp_port->tp_flags &= ~(TPF_READ_SP|
00488                                         TPF_READ_IP);
00489                                 read_ip_packets(tcp_port);
00490                         }
00491                         else
00492                                 tcp_port->tp_flags &= ~TPF_READ_IP;
00493                 }
00494                 else
00495                 {
00496                         assert(!offset);        
00497                         /* this is an invalid assertion but ip sends
00498                           * only whole datagrams up */
00499                         tcp_put_pkt(fd, data, bf_bufsize(data));
00500                 }
00501                 break;
00502         default:
00503                 printf(
00504                 "tcp_put_data(%d, 0x%x, %p) called but tp_state= 0x%x\n",
00505                         fd, offset, data, tcp_port->tp_state);
00506                 break;
00507         }
00508         return NW_OK;
00509 }
00510 
00511 /*
00512 tcp_put_pkt
00513 */
00514 
00515 PRIVATE void tcp_put_pkt(fd, data, datalen)
00516 int fd;
00517 acc_t *data;
00518 size_t datalen;
00519 {
00520         tcp_port_t *tcp_port;
00521         tcp_conn_t *tcp_conn, **conn_p;
00522         ip_hdr_t *ip_hdr;
00523         tcp_hdr_t *tcp_hdr;
00524         acc_t *ip_pack, *tcp_pack;
00525         size_t ip_datalen, tcp_datalen, ip_hdr_len, tcp_hdr_len;
00526         u16_t sum, mtu;
00527         u32_t bits;
00528         int i, hash;
00529         ipaddr_t srcaddr, dstaddr, ipaddr, mask;
00530         tcpport_t srcport, dstport;
00531 
00532         tcp_port= &tcp_port_table[fd];
00533 
00534         /* Extract the IP header. */
00535         ip_hdr= (ip_hdr_t *)ptr2acc_data(data);
00536         ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
00537         ip_datalen= datalen - ip_hdr_len;
00538         if (ip_datalen == 0)
00539         {
00540                 if (ip_hdr->ih_proto == 0)
00541                 {
00542                         /* IP layer reports new IP address */
00543                         ipaddr= ip_hdr->ih_src;
00544                         mask= ip_hdr->ih_dst;
00545                         mtu= ntohs(ip_hdr->ih_length);
00546                         tcp_port->tp_ipaddr= ipaddr;
00547                         tcp_port->tp_subnetmask= mask;
00548                         tcp_port->tp_mtu= mtu;
00549                         DBLOCK(1, printf("tcp_put_pkt: using address ");
00550                                 writeIpAddr(ipaddr);
00551                                 printf(", netmask ");
00552                                 writeIpAddr(mask);
00553                                 printf(", mtu %u\n", mtu));
00554                         for (i= 0, tcp_conn= tcp_conn_table+i;
00555                                 i<TCP_CONN_NR; i++, tcp_conn++)
00556                         {
00557                                 if (!(tcp_conn->tc_flags & TCF_INUSE))
00558                                         continue;
00559                                 if (tcp_conn->tc_port != tcp_port)
00560                                         continue;
00561                                 tcp_conn->tc_locaddr= ipaddr;
00562                         }
00563                 }
00564                 else
00565                         DBLOCK(1, printf("tcp_put_pkt: no TCP header\n"));
00566                 bf_afree(data);
00567                 return;
00568         }
00569         data->acc_linkC++;
00570         ip_pack= data;
00571         ip_pack= bf_align(ip_pack, ip_hdr_len, 4);
00572         ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_pack);
00573         data= bf_delhead(data, ip_hdr_len);
00574 
00575         /* Compute the checksum */
00576         sum= tcp_pack_oneCsum(ip_hdr, data);
00577 
00578         /* Extract the TCP header */
00579         if (ip_datalen < TCP_MIN_HDR_SIZE)
00580         {
00581                 DBLOCK(1, printf("truncated TCP header\n"));
00582                 bf_afree(ip_pack);
00583                 bf_afree(data);
00584                 return;
00585         }
00586         data= bf_packIffLess(data, TCP_MIN_HDR_SIZE);
00587         tcp_hdr= (tcp_hdr_t *)ptr2acc_data(data);
00588         tcp_hdr_len= (tcp_hdr->th_data_off & TH_DO_MASK) >> 2;
00589                 /* actualy (>> 4) << 2 */
00590         if (ip_datalen < tcp_hdr_len || tcp_hdr_len < TCP_MIN_HDR_SIZE)
00591         {
00592                 if (tcp_hdr_len < TCP_MIN_HDR_SIZE)
00593                 {
00594                         DBLOCK(1, printf("strange tcp header length %d\n",
00595                                 tcp_hdr_len));
00596                 }
00597                 else
00598                 {
00599                         DBLOCK(1, printf("truncated TCP header\n"));
00600                 }
00601                 bf_afree(ip_pack);
00602                 bf_afree(data);
00603                 return;
00604         }
00605         data->acc_linkC++;
00606         tcp_pack= data;
00607         tcp_pack= bf_align(tcp_pack, tcp_hdr_len, 4);
00608         tcp_hdr= (tcp_hdr_t *)ptr2acc_data(tcp_pack);
00609         if (ip_datalen == tcp_hdr_len)
00610         {
00611                 bf_afree(data);
00612                 data= NULL;
00613         }
00614         else
00615                 data= bf_delhead(data, tcp_hdr_len);
00616         tcp_datalen= ip_datalen-tcp_hdr_len;
00617 
00618         if ((u16_t)~sum)
00619         {
00620                 DBLOCK(1, printf("checksum error in tcp packet\n");
00621                         printf("tcp_pack_oneCsum(...)= 0x%x length= %d\n", 
00622                         (u16_t)~sum, tcp_datalen);
00623                         printf("src ip_addr= "); writeIpAddr(ip_hdr->ih_src);
00624                         printf("\n"));
00625                 bf_afree(ip_pack);
00626                 bf_afree(tcp_pack);
00627                 bf_afree(data);
00628                 return;
00629         }
00630 
00631         srcaddr= ip_hdr->ih_src;
00632         dstaddr= ip_hdr->ih_dst;
00633         srcport= tcp_hdr->th_srcport;
00634         dstport= tcp_hdr->th_dstport;
00635         bits= srcaddr ^ dstaddr ^ srcport ^ dstport;
00636         bits= (bits >> 16) ^ bits;
00637         bits= (bits >> 8) ^ bits;
00638         hash= ((bits >> TCP_CONN_HASH_SHIFT) ^ bits) & (TCP_CONN_HASH_NR-1);
00639         conn_p= tcp_port->tp_conn_hash[hash];
00640         if (conn_p[0]->tc_locport == dstport &&
00641                 conn_p[0]->tc_remport == srcport &&
00642                 conn_p[0]->tc_remaddr == srcaddr &&
00643                 conn_p[0]->tc_locaddr == dstaddr)
00644         {
00645                 tcp_conn= conn_p[0];
00646         }
00647         else if (conn_p[1]->tc_locport == dstport &&
00648                 conn_p[1]->tc_remport == srcport &&
00649                 conn_p[1]->tc_remaddr == srcaddr &&
00650                 conn_p[1]->tc_locaddr == dstaddr)
00651         {
00652                 tcp_conn= conn_p[1];
00653                 conn_p[1]= conn_p[0];
00654                 conn_p[0]= tcp_conn;
00655         }
00656         else if (conn_p[2]->tc_locport == dstport &&
00657                 conn_p[2]->tc_remport == srcport &&
00658                 conn_p[2]->tc_remaddr == srcaddr &&
00659                 conn_p[2]->tc_locaddr == dstaddr)
00660         {
00661                 tcp_conn= conn_p[2];
00662                 conn_p[2]= conn_p[1];
00663                 conn_p[1]= conn_p[0];
00664                 conn_p[0]= tcp_conn;
00665         }
00666         else if (conn_p[3]->tc_locport == dstport &&
00667                 conn_p[3]->tc_remport == srcport &&
00668                 conn_p[3]->tc_remaddr == srcaddr &&
00669                 conn_p[3]->tc_locaddr == dstaddr)
00670         {
00671                 tcp_conn= conn_p[3];
00672                 conn_p[3]= conn_p[2];
00673                 conn_p[2]= conn_p[1];
00674                 conn_p[1]= conn_p[0];
00675                 conn_p[0]= tcp_conn;
00676         }
00677         else
00678                 tcp_conn= NULL;
00679         if ((tcp_conn != NULL && tcp_conn->tc_state == TCS_CLOSED) ||
00680                 (tcp_hdr->th_flags & THF_SYN))
00681         {
00682                 tcp_conn= NULL;
00683         }
00684 
00685         if (tcp_conn == NULL)
00686         {
00687                 tcp_conn= find_best_conn(ip_hdr, tcp_hdr);
00688                 if (!tcp_conn)
00689                 {
00690                         /* listen backlog hack */
00691                         bf_afree(ip_pack);
00692                         bf_afree(tcp_pack);
00693                         bf_afree(data);
00694                         return;
00695                 }
00696                 if (tcp_conn->tc_state != TCS_CLOSED)
00697                 {
00698                         conn_p[3]= conn_p[2];
00699                         conn_p[2]= conn_p[1];
00700                         conn_p[1]= conn_p[0];
00701                         conn_p[0]= tcp_conn;
00702                 }
00703         }
00704         assert(tcp_conn->tc_busy == 0);
00705         tcp_conn->tc_busy++;
00706         tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, data, tcp_datalen);
00707         tcp_conn->tc_busy--;
00708         bf_afree(ip_pack);
00709         bf_afree(tcp_pack);
00710 }
00711 
00712 
00713 PUBLIC int tcp_open (port, srfd, get_userdata, put_userdata, put_pkt,
00714         select_res)
00715 int port;
00716 int srfd;
00717 get_userdata_t get_userdata;
00718 put_userdata_t put_userdata;
00719 put_pkt_t put_pkt;
00720 select_res_t select_res;
00721 {
00722         int i, j;
00723 
00724         tcp_fd_t *tcp_fd;
00725 
00726         for (i=0; i<TCP_FD_NR && (tcp_fd_table[i].tf_flags & TFF_INUSE);
00727                 i++);
00728         if (i>=TCP_FD_NR)
00729         {
00730                 return EAGAIN;
00731         }
00732 
00733         tcp_fd= &tcp_fd_table[i];
00734 
00735         tcp_fd->tf_flags= TFF_INUSE;
00736         tcp_fd->tf_flags |= TFF_PUSH_DATA;
00737 
00738         tcp_fd->tf_port= &tcp_port_table[port];
00739         tcp_fd->tf_srfd= srfd;
00740         tcp_fd->tf_tcpconf.nwtc_flags= TCP_DEF_CONF;
00741         tcp_fd->tf_tcpconf.nwtc_remaddr= 0;
00742         tcp_fd->tf_tcpconf.nwtc_remport= 0;
00743         tcp_fd->tf_tcpopt.nwto_flags= TCP_DEF_OPT;
00744         tcp_fd->tf_get_userdata= get_userdata;
00745         tcp_fd->tf_put_userdata= put_userdata;
00746         tcp_fd->tf_select_res= select_res;
00747         tcp_fd->tf_conn= 0;
00748         tcp_fd->tf_error= 0;
00749         for (j= 0; j<TFL_LISTEN_MAX; j++)
00750                 tcp_fd->tf_listenq[j]= NULL;
00751         return i;
00752 }
00753 
00754 /*
00755 tcp_ioctl
00756 */
00757 PUBLIC int tcp_ioctl (fd, req)
00758 int fd;
00759 ioreq_t req;
00760 {
00761         tcp_fd_t *tcp_fd;
00762         tcp_port_t *tcp_port;
00763         tcp_conn_t *tcp_conn;
00764         nwio_tcpconf_t *tcp_conf;
00765         nwio_tcpopt_t *tcp_opt;
00766         tcp_cookie_t *cookiep;
00767         acc_t *acc, *conf_acc, *opt_acc;
00768         int result, *bytesp;
00769         u8_t rndbits[RAND256_BUFSIZE];
00770 
00771         tcp_fd= &tcp_fd_table[fd];
00772 
00773         assert (tcp_fd->tf_flags & TFF_INUSE);
00774 
00775         tcp_port= tcp_fd->tf_port;
00776         tcp_fd->tf_flags |= TFF_IOCTL_IP;
00777         tcp_fd->tf_ioreq= req;
00778 
00779         if (tcp_port->tp_state != TPS_MAIN)
00780         {
00781                 tcp_fd->tf_flags |= TFF_IOC_INIT_SP;
00782                 return NW_SUSPEND;
00783         }
00784 
00785         switch (req)
00786         {
00787         case NWIOSTCPCONF:
00788                 if ((tcp_fd->tf_flags & TFF_CONNECTED) ||
00789                         (tcp_fd->tf_flags & TFF_CONNECTING) ||
00790                         (tcp_fd->tf_flags & TFF_LISTENQ))
00791                 {
00792                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00793                         reply_thr_get (tcp_fd, EISCONN, TRUE);
00794                         result= NW_OK;
00795                         break;
00796                 }
00797                 result= tcp_setconf(tcp_fd);
00798                 break;
00799         case NWIOGTCPCONF:
00800                 conf_acc= bf_memreq(sizeof(*tcp_conf));
00801 assert (conf_acc->acc_length == sizeof(*tcp_conf));
00802                 tcp_conf= (nwio_tcpconf_t *)ptr2acc_data(conf_acc);
00803 
00804                 *tcp_conf= tcp_fd->tf_tcpconf;
00805                 if (tcp_fd->tf_flags & TFF_CONNECTED)
00806                 {
00807                         tcp_conn= tcp_fd->tf_conn;
00808                         tcp_conf->nwtc_locport= tcp_conn->tc_locport;
00809                         tcp_conf->nwtc_remaddr= tcp_conn->tc_remaddr;
00810                         tcp_conf->nwtc_remport= tcp_conn->tc_remport;
00811                 }
00812                 tcp_conf->nwtc_locaddr= tcp_fd->tf_port->tp_ipaddr;
00813                 result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
00814                         0, conf_acc, TRUE);
00815                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00816                 reply_thr_put(tcp_fd, result, TRUE);
00817                 result= NW_OK;
00818                 break;
00819         case NWIOSTCPOPT:
00820                 result= tcp_setopt(tcp_fd);
00821                 break;
00822         case NWIOGTCPOPT:
00823                 opt_acc= bf_memreq(sizeof(*tcp_opt));
00824                 assert (opt_acc->acc_length == sizeof(*tcp_opt));
00825                 tcp_opt= (nwio_tcpopt_t *)ptr2acc_data(opt_acc);
00826 
00827                 *tcp_opt= tcp_fd->tf_tcpopt;
00828                 result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
00829                         0, opt_acc, TRUE);
00830                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00831                 reply_thr_put(tcp_fd, result, TRUE);
00832                 result= NW_OK;
00833                 break;
00834         case NWIOTCPCONN:
00835                 if (tcp_fd->tf_flags & TFF_CONNECTING)
00836                 {
00837                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00838                         reply_thr_get (tcp_fd, EALREADY, TRUE);
00839                         result= NW_OK;
00840                         break;
00841                 }
00842                 if (tcp_fd->tf_flags & TFF_CONNECTED)
00843                 {
00844                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00845                         reply_thr_get (tcp_fd, EISCONN, TRUE);
00846                         result= NW_OK;
00847                         break;
00848                 }
00849                 result= tcp_connect(tcp_fd);
00850                 if (result == NW_OK)
00851                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00852                 break;
00853         case NWIOTCPLISTEN:
00854         case NWIOTCPLISTENQ:
00855                 if ((tcp_fd->tf_flags & TFF_CONNECTED) ||
00856                         (tcp_fd->tf_flags & TFF_LISTENQ) ||
00857                         (tcp_fd->tf_flags & TFF_CONNECTING))
00858                 {
00859                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00860                         reply_thr_get (tcp_fd, EISCONN, TRUE);
00861                         result= NW_OK;
00862                         break;
00863                 }
00864                 result= tcp_listen(tcp_fd, (req == NWIOTCPLISTENQ));
00865                 break;
00866         case NWIOTCPSHUTDOWN:
00867                 if (!(tcp_fd->tf_flags & TFF_CONNECTED))
00868                 {
00869                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00870                         reply_thr_get (tcp_fd, ENOTCONN, TRUE);
00871                         result= NW_OK;
00872                         break;
00873                 }
00874                 tcp_fd->tf_flags |= TFF_IOCTL_IP;
00875                 tcp_fd->tf_ioreq= req;
00876                 tcp_conn= tcp_fd->tf_conn;
00877 
00878                 tcp_conn->tc_busy++;
00879                 tcp_fd_write(tcp_conn);
00880                 tcp_conn->tc_busy--;
00881                 tcp_conn_write(tcp_conn, 0);
00882                 if (!(tcp_fd->tf_flags & TFF_IOCTL_IP))
00883                         result= NW_OK;
00884                 else
00885                         result= NW_SUSPEND;
00886                 break;
00887         case NWIOTCPPUSH:
00888                 if (!(tcp_fd->tf_flags & TFF_CONNECTED))
00889                 {
00890                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00891                         reply_thr_get (tcp_fd, ENOTCONN, TRUE);
00892                         result= NW_OK;
00893                         break;
00894                 }
00895                 tcp_conn= tcp_fd->tf_conn;
00896                 tcp_conn->tc_SND_PSH= tcp_conn->tc_SND_NXT;
00897                 tcp_conn->tc_flags &= ~TCF_NO_PUSH;
00898                 tcp_conn->tc_flags |= TCF_PUSH_NOW;
00899 
00900                 /* Start the timer (if necessary) */
00901                 if (tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_UNA)
00902                         tcp_set_send_timer(tcp_conn);
00903 
00904                 tcp_conn_write(tcp_conn, 0);
00905                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00906                 reply_thr_get (tcp_fd, NW_OK, TRUE);
00907                 result= NW_OK;
00908                 break;
00909         case NWIOGTCPCOOKIE:
00910                 if (!(tcp_fd->tf_flags & TFF_COOKIE))
00911                 {
00912                         tcp_fd->tf_cookie.tc_ref= fd;
00913                         rand256(rndbits);
00914                         assert(sizeof(tcp_fd->tf_cookie.tc_secret) <=
00915                                 RAND256_BUFSIZE);
00916                         memcpy(tcp_fd->tf_cookie.tc_secret, 
00917                                 rndbits, sizeof(tcp_fd->tf_cookie.tc_secret));
00918                         tcp_fd->tf_flags |= TFF_COOKIE;
00919                 }
00920                 acc= bf_memreq(sizeof(*cookiep));
00921                 cookiep= (tcp_cookie_t *)ptr2acc_data(acc);
00922 
00923                 *cookiep= tcp_fd->tf_cookie;
00924                 result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
00925                         0, acc, TRUE);
00926                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00927                 reply_thr_put(tcp_fd, result, TRUE);
00928                 result= NW_OK;
00929                 break;
00930         case NWIOTCPACCEPTTO:
00931                 result= tcp_acceptto(tcp_fd);
00932                 break;
00933         case FIONREAD:
00934                 acc= bf_memreq(sizeof(*bytesp));
00935                 bytesp= (int *)ptr2acc_data(acc);
00936                 tcp_bytesavailable(tcp_fd, bytesp);
00937                 result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
00938                         0, acc, TRUE);
00939                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00940                 reply_thr_put(tcp_fd, result, TRUE);
00941                 result= NW_OK;
00942                 break;
00943 
00944         case NWIOTCPGERROR:
00945                 acc= bf_memreq(sizeof(*bytesp));
00946                 bytesp= (int *)ptr2acc_data(acc);
00947                 *bytesp= -tcp_fd->tf_error;     /* Errors are positive in
00948                                                  * user space.
00949                                                  */
00950                 tcp_fd->tf_error= 0;
00951                 result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
00952                         0, acc, TRUE);
00953                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00954                 reply_thr_put(tcp_fd, result, TRUE);
00955                 result= NW_OK;
00956                 break;
00957 
00958         default:
00959                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
00960                 reply_thr_get(tcp_fd, EBADIOCTL, TRUE);
00961                 result= NW_OK;
00962                 break;
00963         }
00964         return result;
00965 }
00966 
00967 
00968 /*
00969 tcp_setconf
00970 */
00971 
00972 PRIVATE int tcp_setconf(tcp_fd)
00973 tcp_fd_t *tcp_fd;
00974 {
00975         nwio_tcpconf_t *tcpconf;
00976         nwio_tcpconf_t oldconf, newconf;
00977         acc_t *data;
00978         tcp_fd_t *fd_ptr;
00979         unsigned int new_en_flags, new_di_flags,
00980                 old_en_flags, old_di_flags, all_flags, flags;
00981         int i;
00982 
00983         data= (*tcp_fd->tf_get_userdata)
00984                 (tcp_fd->tf_srfd, 0,
00985                 sizeof(nwio_tcpconf_t), TRUE);
00986 
00987         if (!data)
00988                 return EFAULT;
00989 
00990         data= bf_packIffLess(data, sizeof(nwio_tcpconf_t));
00991 assert (data->acc_length == sizeof(nwio_tcpconf_t));
00992 
00993         tcpconf= (nwio_tcpconf_t *)ptr2acc_data(data);
00994         oldconf= tcp_fd->tf_tcpconf;
00995         newconf= *tcpconf;
00996 
00997         old_en_flags= oldconf.nwtc_flags & 0xffff;
00998         old_di_flags= (oldconf.nwtc_flags >> 16) &
00999                 0xffff;
01000         new_en_flags= newconf.nwtc_flags & 0xffff;
01001         new_di_flags= (newconf.nwtc_flags >> 16) &
01002                 0xffff;
01003         if (new_en_flags & new_di_flags)
01004         {
01005                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01006                 reply_thr_get(tcp_fd, EBADMODE, TRUE);
01007                 bf_afree(data);
01008                 return NW_OK;
01009         }
01010 
01011         /* NWTC_ACC_MASK */
01012         if (new_di_flags & NWTC_ACC_MASK)
01013         {
01014                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01015                 reply_thr_get(tcp_fd, EBADMODE, TRUE);
01016                 bf_afree(data);
01017                 return NW_OK;
01018                 /* access modes can't be disabled */
01019         }
01020 
01021         if (!(new_en_flags & NWTC_ACC_MASK))
01022                 new_en_flags |= (old_en_flags & NWTC_ACC_MASK);
01023         
01024         /* NWTC_LOCPORT_MASK */
01025         if (new_di_flags & NWTC_LOCPORT_MASK)
01026         {
01027                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01028                 reply_thr_get(tcp_fd, EBADMODE, TRUE);
01029                 bf_afree(data);
01030                 return NW_OK;
01031                 /* the loc ports can't be disabled */
01032         }
01033         if (!(new_en_flags & NWTC_LOCPORT_MASK))
01034         {
01035                 new_en_flags |= (old_en_flags &
01036                         NWTC_LOCPORT_MASK);
01037                 newconf.nwtc_locport= oldconf.nwtc_locport;
01038         }
01039         else if ((new_en_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL)
01040         {
01041                 newconf.nwtc_locport= find_unused_port(tcp_fd-
01042                         tcp_fd_table);
01043         }
01044         else if ((new_en_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET)
01045         {
01046                 if (!newconf.nwtc_locport)
01047                 {
01048                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01049                         reply_thr_get(tcp_fd, EBADMODE, TRUE);
01050                         bf_afree(data);
01051                         return NW_OK;
01052                 }
01053         }
01054         
01055         /* NWTC_REMADDR_MASK */
01056         if (!((new_en_flags | new_di_flags) &
01057                 NWTC_REMADDR_MASK))
01058         {
01059                 new_en_flags |= (old_en_flags &
01060                         NWTC_REMADDR_MASK);
01061                 new_di_flags |= (old_di_flags &
01062                         NWTC_REMADDR_MASK);
01063                 newconf.nwtc_remaddr= oldconf.nwtc_remaddr;
01064         }
01065         else if (new_en_flags & NWTC_SET_RA)
01066         {
01067                 if (!newconf.nwtc_remaddr)
01068                 {
01069                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01070                         reply_thr_get(tcp_fd, EBADMODE, TRUE);
01071                         bf_afree(data);
01072                         return NW_OK;
01073                 }
01074         }
01075         else
01076         {
01077 assert (new_di_flags & NWTC_REMADDR_MASK);
01078                 newconf.nwtc_remaddr= 0;
01079         }
01080 
01081         /* NWTC_REMPORT_MASK */
01082         if (!((new_en_flags | new_di_flags) & NWTC_REMPORT_MASK))
01083         {
01084                 new_en_flags |= (old_en_flags &
01085                         NWTC_REMPORT_MASK);
01086                 new_di_flags |= (old_di_flags &
01087                         NWTC_REMPORT_MASK);
01088                 newconf.nwtc_remport=
01089                         oldconf.nwtc_remport;
01090         }
01091         else if (new_en_flags & NWTC_SET_RP)
01092         {
01093                 if (!newconf.nwtc_remport)
01094                 {
01095                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01096                         reply_thr_get(tcp_fd, EBADMODE, TRUE);
01097                         bf_afree(data);
01098                         return NW_OK;
01099                 }
01100         }
01101         else
01102         {
01103 assert (new_di_flags & NWTC_REMPORT_MASK);
01104                 newconf.nwtc_remport= 0;
01105         }
01106 
01107         newconf.nwtc_flags= ((unsigned long)new_di_flags
01108                 << 16) | new_en_flags;
01109         all_flags= new_en_flags | new_di_flags;
01110 
01111         /* check the access modes */
01112         if ((all_flags & NWTC_LOCPORT_MASK) != NWTC_LP_UNSET)
01113         {
01114                 for (i=0, fd_ptr= tcp_fd_table; i<TCP_FD_NR; i++, fd_ptr++)
01115                 {
01116                         if (fd_ptr == tcp_fd)
01117                                 continue;
01118                         if (!(fd_ptr->tf_flags & TFF_INUSE))
01119                                 continue;
01120                         if (fd_ptr->tf_port != tcp_fd->tf_port)
01121                                 continue;
01122                         flags= fd_ptr->tf_tcpconf.nwtc_flags;
01123                         if ((flags & NWTC_LOCPORT_MASK) == NWTC_LP_UNSET)
01124                                 continue;
01125                         if (fd_ptr->tf_tcpconf.nwtc_locport !=
01126                                 newconf.nwtc_locport)
01127                                 continue;
01128                         if ((flags & NWTC_ACC_MASK) != (all_flags  &
01129                                 NWTC_ACC_MASK) ||
01130                                 (all_flags & NWTC_ACC_MASK) == NWTC_EXCL)
01131                         {
01132                                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01133                                 reply_thr_get(tcp_fd, EADDRINUSE, TRUE);
01134                                 bf_afree(data);
01135                                 return NW_OK;
01136                         }
01137                 }
01138         }
01139                                 
01140         tcp_fd->tf_tcpconf= newconf;
01141 
01142         if ((all_flags & NWTC_ACC_MASK) &&
01143                 ((all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET ||
01144                 (all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL) &&
01145                 (all_flags & NWTC_REMADDR_MASK) &&
01146                 (all_flags & NWTC_REMPORT_MASK))
01147                 tcp_fd->tf_flags |= TFF_CONF_SET;
01148         else
01149         {
01150                 tcp_fd->tf_flags &= ~TFF_CONF_SET;
01151         }
01152         bf_afree(data);
01153         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01154         reply_thr_get(tcp_fd, NW_OK, TRUE);
01155         return NW_OK;
01156 }
01157 
01158 
01159 /*
01160 tcp_setopt
01161 */
01162 
01163 PRIVATE int tcp_setopt(tcp_fd)
01164 tcp_fd_t *tcp_fd;
01165 {
01166         nwio_tcpopt_t *tcpopt;
01167         nwio_tcpopt_t oldopt, newopt;
01168         acc_t *data;
01169         unsigned int new_en_flags, new_di_flags,
01170                 old_en_flags, old_di_flags;
01171 
01172         data= (*tcp_fd->tf_get_userdata) (tcp_fd->tf_srfd, 0,
01173                 sizeof(nwio_tcpopt_t), TRUE);
01174 
01175         if (!data)
01176                 return EFAULT;
01177 
01178         data= bf_packIffLess(data, sizeof(nwio_tcpopt_t));
01179 assert (data->acc_length == sizeof(nwio_tcpopt_t));
01180 
01181         tcpopt= (nwio_tcpopt_t *)ptr2acc_data(data);
01182         oldopt= tcp_fd->tf_tcpopt;
01183         newopt= *tcpopt;
01184 
01185         old_en_flags= oldopt.nwto_flags & 0xffff;
01186         old_di_flags= (oldopt.nwto_flags >> 16) & 0xffff;
01187         new_en_flags= newopt.nwto_flags & 0xffff;
01188         new_di_flags= (newopt.nwto_flags >> 16) & 0xffff;
01189         if (new_en_flags & new_di_flags)
01190         {
01191                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01192                 reply_thr_get(tcp_fd, EBADMODE, TRUE);
01193                 return NW_OK;
01194         }
01195 
01196         /* NWTO_SND_URG_MASK */
01197         if (!((new_en_flags | new_di_flags) & NWTO_SND_URG_MASK))
01198         {
01199                 new_en_flags |= (old_en_flags & NWTO_SND_URG_MASK);
01200                 new_di_flags |= (old_di_flags & NWTO_SND_URG_MASK);
01201         }
01202 
01203         /* NWTO_RCV_URG_MASK */
01204         if (!((new_en_flags | new_di_flags) & NWTO_RCV_URG_MASK))
01205         {
01206                 new_en_flags |= (old_en_flags & NWTO_RCV_URG_MASK);
01207                 new_di_flags |= (old_di_flags & NWTO_RCV_URG_MASK);
01208         }
01209 
01210         /* NWTO_BSD_URG_MASK */
01211         if (!((new_en_flags | new_di_flags) & NWTO_BSD_URG_MASK))
01212         {
01213                 new_en_flags |= (old_en_flags & NWTO_BSD_URG_MASK);
01214                 new_di_flags |= (old_di_flags & NWTO_BSD_URG_MASK);
01215         }
01216         else
01217         {
01218                 if (tcp_fd->tf_conn == NULL)
01219                 {
01220                         bf_afree(data);
01221                         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01222                         reply_thr_get(tcp_fd, EINVAL, TRUE);
01223                         return NW_OK;
01224                 }
01225         }
01226 
01227         /* NWTO_DEL_RST_MASK */
01228         if (!((new_en_flags | new_di_flags) & NWTO_DEL_RST_MASK))
01229         {
01230                 new_en_flags |= (old_en_flags & NWTO_DEL_RST_MASK);
01231                 new_di_flags |= (old_di_flags & NWTO_DEL_RST_MASK);
01232         }
01233 
01234         /* NWTO_BULK_MASK */
01235         if (!((new_en_flags | new_di_flags) & NWTO_BULK_MASK))
01236         {
01237                 new_en_flags |= (old_en_flags & NWTO_BULK_MASK);
01238                 new_di_flags |= (old_di_flags & NWTO_BULK_MASK);
01239         }
01240 
01241         newopt.nwto_flags= ((unsigned long)new_di_flags << 16) |
01242                 new_en_flags;
01243         tcp_fd->tf_tcpopt= newopt;
01244         if (newopt.nwto_flags & NWTO_SND_URG)
01245                 tcp_fd->tf_flags |= TFF_WR_URG;
01246         else
01247                 tcp_fd->tf_flags &= ~TFF_WR_URG;
01248 
01249         if (newopt.nwto_flags & NWTO_RCV_URG)
01250                 tcp_fd->tf_flags |= TFF_RECV_URG;
01251         else
01252                 tcp_fd->tf_flags &= ~TFF_RECV_URG;
01253 
01254         if (tcp_fd->tf_conn)
01255         {
01256                 if (newopt.nwto_flags & NWTO_BSD_URG)
01257                         tcp_fd->tf_conn->tc_flags |= TCF_BSD_URG;
01258                 else
01259                         tcp_fd->tf_conn->tc_flags &= ~TCF_BSD_URG;
01260         }
01261 
01262         if (newopt.nwto_flags & NWTO_DEL_RST)
01263                 tcp_fd->tf_flags |= TFF_DEL_RST;
01264         else
01265                 tcp_fd->tf_flags &= ~TFF_DEL_RST;
01266 
01267         if (newopt.nwto_flags & NWTO_BULK)
01268                 tcp_fd->tf_flags &= ~TFF_PUSH_DATA;
01269         else
01270                 tcp_fd->tf_flags |= TFF_PUSH_DATA;
01271 
01272         bf_afree(data);
01273         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01274         reply_thr_get(tcp_fd, NW_OK, TRUE);
01275         return NW_OK;
01276 }
01277 
01278 
01279 PRIVATE tcpport_t find_unused_port(fd)
01280 int fd;
01281 {
01282         tcpport_t port, nw_port;
01283 
01284         for (port= 0x8000+fd; port < 0xffff-TCP_FD_NR; port+= TCP_FD_NR)
01285         {
01286                 nw_port= htons(port);
01287                 if (is_unused_port(nw_port))
01288                         return nw_port;
01289         }
01290         for (port= 0x8000; port < 0xffff; port++)
01291         {
01292                 nw_port= htons(port);
01293                 if (is_unused_port(nw_port))
01294                         return nw_port;
01295         }
01296         ip_panic(( "unable to find unused port (shouldn't occur)" ));
01297         return 0;
01298 }
01299 
01300 PRIVATE int is_unused_port(port)
01301 tcpport_t port;
01302 {
01303         int i;
01304         tcp_fd_t *tcp_fd;
01305         tcp_conn_t *tcp_conn;
01306 
01307         for (i= 0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++,
01308                 tcp_fd++)
01309         {
01310                 if (!(tcp_fd->tf_flags & TFF_CONF_SET))
01311                         continue;
01312                 if (tcp_fd->tf_tcpconf.nwtc_locport == port)
01313                         return FALSE;
01314         }
01315         for (i= tcp_conf_nr, tcp_conn= tcp_conn_table+i;
01316                 i<TCP_CONN_NR; i++, tcp_conn++)
01317                 /* the first tcp_conf_nr ports are special */
01318         {
01319                 if (!(tcp_conn->tc_flags & TCF_INUSE))
01320                         continue;
01321                 if (tcp_conn->tc_locport == port)
01322                         return FALSE;
01323         }
01324         return TRUE;
01325 }
01326 
01327 PRIVATE int reply_thr_put(tcp_fd, reply, for_ioctl)
01328 tcp_fd_t *tcp_fd;
01329 int reply;
01330 int for_ioctl;
01331 {
01332         assert (tcp_fd);
01333 
01334         return (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd, reply,
01335                 (acc_t *)0, for_ioctl);
01336 }
01337 
01338 PRIVATE void reply_thr_get(tcp_fd, reply, for_ioctl)
01339 tcp_fd_t *tcp_fd;
01340 int reply;
01341 int for_ioctl;
01342 {
01343         acc_t *result;
01344 
01345         result= (*tcp_fd->tf_get_userdata)(tcp_fd->tf_srfd, reply,
01346                 (size_t)0, for_ioctl);
01347         assert (!result);
01348 }
01349 
01350 PUBLIC int tcp_su4listen(tcp_fd, tcp_conn, do_listenq)
01351 tcp_fd_t *tcp_fd;
01352 tcp_conn_t *tcp_conn;
01353 int do_listenq;
01354 {
01355         tcp_conn->tc_locport= tcp_fd->tf_tcpconf.nwtc_locport;
01356         tcp_conn->tc_locaddr= tcp_fd->tf_port->tp_ipaddr;
01357         if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP)
01358                 tcp_conn->tc_remport= tcp_fd->tf_tcpconf.nwtc_remport;
01359         else
01360                 tcp_conn->tc_remport= 0;
01361         if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA)
01362                 tcp_conn->tc_remaddr= tcp_fd->tf_tcpconf.nwtc_remaddr;
01363         else
01364                 tcp_conn->tc_remaddr= 0;
01365 
01366         tcp_setup_conn(tcp_fd->tf_port, tcp_conn);
01367         tcp_conn->tc_fd= tcp_fd;
01368         tcp_conn->tc_connInprogress= 1;
01369         tcp_conn->tc_orglisten= TRUE;
01370         tcp_conn->tc_state= TCS_LISTEN;
01371         tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_LISTEN;
01372         if (do_listenq)
01373         {
01374                 tcp_fd->tf_flags |= TFF_LISTENQ;
01375                 tcp_reply_ioctl(tcp_fd, NW_OK);
01376                 return NW_OK;
01377         }
01378         return NW_SUSPEND;
01379 }
01380 
01381 /*
01382 find_empty_conn
01383 
01384 This function returns a connection that is not inuse.
01385 This includes connections that are never used, and connections without a
01386 user that are not used for a while.
01387 */
01388 
01389 PRIVATE tcp_conn_t *find_empty_conn()
01390 {
01391         int i;
01392         tcp_conn_t *tcp_conn;
01393 
01394         for (i=tcp_conf_nr, tcp_conn= tcp_conn_table+i;
01395                 i<TCP_CONN_NR; i++, tcp_conn++)
01396                 /* the first tcp_conf_nr connections are reserved for
01397                  * RSTs
01398                  */
01399         {
01400                 if (tcp_conn->tc_flags == TCF_EMPTY)
01401                 {
01402                         tcp_conn->tc_connInprogress= 0;
01403                         tcp_conn->tc_fd= NULL;
01404                         return tcp_conn;
01405                 }
01406                 if (tcp_conn->tc_fd)
01407                         continue;
01408                 if (tcp_conn->tc_senddis > get_time())
01409                         continue;
01410                 if (tcp_conn->tc_state != TCS_CLOSED)
01411                 {
01412                          tcp_close_connection (tcp_conn, ENOCONN);
01413                 }
01414                 tcp_conn->tc_flags= 0;
01415                 return tcp_conn;
01416         }
01417         return NULL;
01418 }
01419 
01420 
01421 /*
01422 find_conn_entry
01423 
01424 This function return a connection matching locport, locaddr, remport, remaddr.
01425 If no such connection exists NULL is returned.
01426 If a connection exists without mainuser it is closed.
01427 */
01428 
01429 PRIVATE tcp_conn_t *find_conn_entry(locport, locaddr, remport, remaddr)
01430 tcpport_t locport;
01431 ipaddr_t locaddr;
01432 tcpport_t remport;
01433 ipaddr_t remaddr;
01434 {
01435         tcp_conn_t *tcp_conn;
01436         int i, state;
01437 
01438         assert(remport);
01439         assert(remaddr);
01440         for (i=tcp_conf_nr, tcp_conn= tcp_conn_table+i; i<TCP_CONN_NR;
01441                 i++, tcp_conn++)
01442                 /* the first tcp_conf_nr connections are reserved for
01443                         RSTs */
01444         {
01445                 if (tcp_conn->tc_flags == TCF_EMPTY)
01446                         continue;
01447                 if (tcp_conn->tc_locport != locport ||
01448                         tcp_conn->tc_locaddr != locaddr ||
01449                         tcp_conn->tc_remport != remport ||
01450                         tcp_conn->tc_remaddr != remaddr)
01451                         continue;
01452                 if (tcp_conn->tc_fd)
01453                         return tcp_conn;
01454                 state= tcp_conn->tc_state;
01455                 if (state != TCS_CLOSED)
01456                 {
01457                         tcp_close_connection(tcp_conn, ENOCONN);
01458                 }
01459                 return tcp_conn;
01460         }
01461         return NULL;
01462 }
01463 
01464 PRIVATE void read_ip_packets(tcp_port)
01465 tcp_port_t *tcp_port;
01466 {
01467         int result;
01468 
01469         do
01470         {
01471                 tcp_port->tp_flags |= TPF_READ_IP;
01472                 result= ip_read(tcp_port->tp_ipfd, TCP_MAX_DATAGRAM);
01473                 if (result == NW_SUSPEND)
01474                 {
01475                         tcp_port->tp_flags |= TPF_READ_SP;
01476                         return;
01477                 }
01478                 assert(result == NW_OK);
01479                 tcp_port->tp_flags &= ~TPF_READ_IP;
01480         } while(!(tcp_port->tp_flags & TPF_READ_IP));
01481 }
01482 
01483 /*
01484 find_best_conn
01485 */
01486 
01487 PRIVATE tcp_conn_t *find_best_conn(ip_hdr, tcp_hdr)
01488 ip_hdr_t *ip_hdr;
01489 tcp_hdr_t *tcp_hdr;
01490 {
01491         
01492         int best_level, new_level;
01493         tcp_conn_t *best_conn, *listen_conn, *tcp_conn;
01494         tcp_fd_t *tcp_fd;
01495         int i;
01496         ipaddr_t locaddr;
01497         ipaddr_t remaddr;
01498         tcpport_t locport;
01499         tcpport_t remport;
01500 
01501         locaddr= ip_hdr->ih_dst;
01502         remaddr= ip_hdr->ih_src;
01503         locport= tcp_hdr->th_dstport;
01504         remport= tcp_hdr->th_srcport;
01505         if (!remport)   /* This can interfere with a listen, so we reject it
01506                          * by clearing the requested port 
01507                          */
01508                 locport= 0;
01509                 
01510         best_level= 0;
01511         best_conn= NULL;
01512         listen_conn= NULL;
01513         for (i= tcp_conf_nr, tcp_conn= tcp_conn_table+i;
01514                 i<TCP_CONN_NR; i++, tcp_conn++)
01515                 /* the first tcp_conf_nr connections are reserved for
01516                         RSTs */
01517         {
01518                 if (!(tcp_conn->tc_flags & TCF_INUSE))
01519                         continue;
01520                 /* First fast check for open connections. */
01521                 if (tcp_conn->tc_locaddr == locaddr && 
01522                         tcp_conn->tc_locport == locport &&
01523                         tcp_conn->tc_remport == remport &&
01524                         tcp_conn->tc_remaddr == remaddr &&
01525                         tcp_conn->tc_fd)
01526                 {
01527                         return tcp_conn;
01528                 }
01529 
01530                 /* Now check for listens and abandoned connections. */
01531                 if (tcp_conn->tc_locaddr != locaddr)
01532                 {
01533                         continue;
01534                 }
01535                 new_level= 0;
01536                 if (tcp_conn->tc_locport)
01537                 {
01538                         if (tcp_conn->tc_locport != locport)
01539                         {
01540                                 continue;
01541                         }
01542                         new_level += 4;
01543                 }
01544                 if (tcp_conn->tc_remport)
01545                 {
01546                         if (tcp_conn->tc_remport != remport)
01547                         {
01548                                 continue;
01549                         }
01550                         new_level += 1;
01551                 }
01552                 if (tcp_conn->tc_remaddr)
01553                 {
01554                         if (tcp_conn->tc_remaddr != remaddr)
01555                         {
01556                                 continue;
01557                         }
01558                         new_level += 2;
01559                 }
01560                 if (new_level<best_level)
01561                         continue;
01562                 if (new_level != 7 && tcp_conn->tc_state != TCS_LISTEN)
01563                         continue;
01564                 if (new_level == 7)
01565                         /* We found an abandoned connection */
01566                 {
01567                         assert(!tcp_conn->tc_fd);
01568                         if (best_conn && tcp_Lmod4G(tcp_conn->tc_ISS,
01569                                 best_conn->tc_ISS))
01570                         {
01571                                 continue;
01572                         }
01573                         best_conn= tcp_conn;
01574                         continue;
01575                 }
01576                 if (!(tcp_hdr->th_flags & THF_SYN))
01577                         continue;
01578                 best_level= new_level;
01579                 listen_conn= tcp_conn;
01580                 assert(listen_conn->tc_fd != NULL);
01581         }
01582 
01583         if (listen_conn && listen_conn->tc_fd->tf_flags & TFF_LISTENQ &&
01584                 listen_conn->tc_fd->tf_conn == listen_conn)
01585         {
01586                 /* Special processing for listen queues. Only accept the 
01587                  * connection if there is empty space in the queue and
01588                  * there are empty connections as well.
01589                  */
01590                 listen_conn= new_conn_for_queue(listen_conn->tc_fd);
01591         }
01592         
01593         if (!best_conn && !listen_conn)
01594         {
01595                 if ((tcp_hdr->th_flags & THF_SYN) &&
01596                         maybe_listen(locaddr, locport, remaddr, remport))
01597                 {
01598                         /* Quick hack to implement listen back logs:
01599                          * if a SYN arrives and there is no listen waiting
01600                          * for that packet, then no reply is sent.
01601                          */
01602                         return NULL;
01603                 }
01604 
01605                 for (i=0, tcp_conn= tcp_conn_table; i<tcp_conf_nr;
01606                         i++, tcp_conn++)
01607                 {
01608                         /* find valid port to send RST */
01609                         if ((tcp_conn->tc_flags & TCF_INUSE) &&
01610                                 tcp_conn->tc_locaddr==locaddr)
01611                         {
01612                                 break;
01613                         }
01614                 }
01615                 assert (tcp_conn);
01616                 assert (tcp_conn->tc_state == TCS_CLOSED);
01617 
01618                 tcp_conn->tc_locport= locport;
01619                 tcp_conn->tc_locaddr= locaddr;
01620                 tcp_conn->tc_remport= remport;
01621                 tcp_conn->tc_remaddr= remaddr;
01622                 assert (!tcp_conn->tc_fd);
01623                 return tcp_conn;
01624         }
01625 
01626         if (best_conn)
01627         {
01628                 if (!listen_conn)
01629                 {
01630                         assert(!best_conn->tc_fd);
01631                         return best_conn;
01632                 }
01633 
01634                 assert(listen_conn->tc_connInprogress);
01635                 tcp_fd= listen_conn->tc_fd;
01636                 assert(tcp_fd);
01637                 assert((tcp_fd->tf_flags & TFF_LISTENQ) ||
01638                          tcp_fd->tf_conn == listen_conn);
01639 
01640                 if (best_conn->tc_state != TCS_CLOSED)
01641                         tcp_close_connection(best_conn, ENOCONN);
01642 
01643                 listen_conn->tc_ISS= best_conn->tc_ISS;
01644                 if (best_conn->tc_senddis > listen_conn->tc_senddis)
01645                         listen_conn->tc_senddis= best_conn->tc_senddis;
01646                 return listen_conn;
01647         }
01648         assert (listen_conn);
01649         return listen_conn;
01650 }
01651 
01652 /*
01653 new_conn_for_queue
01654 */
01655 PRIVATE tcp_conn_t *new_conn_for_queue(tcp_fd)
01656 tcp_fd_t *tcp_fd;
01657 {
01658         int i;
01659         tcp_conn_t *tcp_conn;
01660 
01661         assert(tcp_fd->tf_flags & TFF_LISTENQ);
01662 
01663         for (i= 0; i<TFL_LISTEN_MAX; i++)
01664         {
01665                 if (tcp_fd->tf_listenq[i] == NULL)
01666                         break;
01667         }
01668         if (i >= TFL_LISTEN_MAX)
01669                 return NULL;
01670 
01671         tcp_conn= find_empty_conn();
01672         if (!tcp_conn)
01673                 return NULL;
01674         tcp_fd->tf_listenq[i]= tcp_conn;
01675         (void)tcp_su4listen(tcp_fd, tcp_conn, 0 /* !do_listenq */);
01676         return tcp_conn;
01677 }
01678 
01679 /*
01680 maybe_listen
01681 */
01682 PRIVATE int maybe_listen(locaddr, locport, remaddr, remport)
01683 ipaddr_t locaddr;
01684 tcpport_t locport;
01685 ipaddr_t remaddr;
01686 tcpport_t remport;
01687 {
01688         int i;
01689         tcp_conn_t *tcp_conn;
01690         tcp_fd_t *fd;
01691 
01692         for (i= tcp_conf_nr, tcp_conn= tcp_conn_table+i;
01693                 i<TCP_CONN_NR; i++, tcp_conn++)
01694         {
01695                 if (!(tcp_conn->tc_flags & TCF_INUSE))
01696                         continue;
01697 
01698                 if (tcp_conn->tc_locaddr != locaddr)
01699                 {
01700                         continue;
01701                 }
01702                 if (tcp_conn->tc_locport != locport )
01703                 {
01704                         continue;
01705                 }
01706                 if (!tcp_conn->tc_orglisten)
01707                         continue;
01708                 fd= tcp_conn->tc_fd;
01709                 if (!fd)
01710                         continue;
01711                 if ((fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP) &&
01712                         tcp_conn->tc_remport != remport)
01713                 {
01714                         continue;
01715                 }
01716                 if ((fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA) &&
01717                         tcp_conn->tc_remaddr != remaddr)
01718                 {
01719                         continue;
01720                 }
01721                 if (!(fd->tf_flags & TFF_DEL_RST))
01722                         continue;
01723                 return 1;
01724 
01725         }
01726         return 0;
01727 }
01728 
01729 
01730 PUBLIC void tcp_reply_ioctl(tcp_fd, reply)
01731 tcp_fd_t *tcp_fd;
01732 int reply;
01733 {
01734         assert (tcp_fd->tf_flags & TFF_IOCTL_IP);
01735         assert (tcp_fd->tf_ioreq == NWIOTCPSHUTDOWN ||
01736                 tcp_fd->tf_ioreq == NWIOTCPLISTEN ||
01737                 tcp_fd->tf_ioreq == NWIOTCPLISTENQ ||
01738                 tcp_fd->tf_ioreq == NWIOTCPACCEPTTO ||
01739                 tcp_fd->tf_ioreq == NWIOTCPCONN);
01740         
01741         tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
01742         reply_thr_get (tcp_fd, reply, TRUE);
01743 }
01744 
01745 PUBLIC void tcp_reply_write(tcp_fd, reply)
01746 tcp_fd_t *tcp_fd;
01747 size_t reply;
01748 {
01749         assert (tcp_fd->tf_flags & TFF_WRITE_IP);
01750 
01751         tcp_fd->tf_flags &= ~TFF_WRITE_IP;
01752         reply_thr_get (tcp_fd, reply, FALSE);
01753 }
01754 
01755 PUBLIC void tcp_reply_read(tcp_fd, reply)
01756 tcp_fd_t *tcp_fd;
01757 size_t reply;
01758 {
01759         assert (tcp_fd->tf_flags & TFF_READ_IP);
01760 
01761         tcp_fd->tf_flags &= ~TFF_READ_IP;
01762         reply_thr_put (tcp_fd, reply, FALSE);
01763 }
01764 
01765 PUBLIC int tcp_write(fd, count)
01766 int fd;
01767 size_t count;
01768 {
01769         tcp_fd_t *tcp_fd;
01770         tcp_conn_t *tcp_conn;
01771 
01772         tcp_fd= &tcp_fd_table[fd];
01773 
01774         assert (tcp_fd->tf_flags & TFF_INUSE);
01775 
01776         if (!(tcp_fd->tf_flags & TFF_CONNECTED))
01777         {
01778                 reply_thr_get (tcp_fd, ENOTCONN, FALSE);
01779                 return NW_OK;
01780         }
01781         tcp_conn= tcp_fd->tf_conn;
01782         if (tcp_conn->tc_state == TCS_CLOSED)
01783         {
01784                 reply_thr_get(tcp_fd, tcp_conn->tc_error, FALSE);
01785                 return NW_OK;
01786         }
01787         if (tcp_conn->tc_flags & TCF_FIN_SENT)
01788         {
01789                 reply_thr_get (tcp_fd, ESHUTDOWN, FALSE);
01790                 return NW_OK;
01791         }
01792 
01793         tcp_fd->tf_flags |= TFF_WRITE_IP;
01794         tcp_fd->tf_write_offset= 0;
01795         tcp_fd->tf_write_count= count;
01796 
01797         /* New data may cause a segment to be sent. Clear PUSH_NOW
01798          * from last NWIOTCPPUSH ioctl.
01799          */
01800         tcp_conn->tc_flags &= ~(TCF_NO_PUSH|TCF_PUSH_NOW);
01801 
01802         /* Start the timer (if necessary) */
01803         if (tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_UNA)
01804                 tcp_set_send_timer(tcp_conn);
01805 
01806         assert(tcp_conn->tc_busy == 0);
01807         tcp_conn->tc_busy++;
01808         tcp_fd_write(tcp_conn);
01809         tcp_conn->tc_busy--;
01810         tcp_conn_write(tcp_conn, 0);
01811 
01812         if (!(tcp_fd->tf_flags & TFF_WRITE_IP))
01813                 return NW_OK;
01814         else
01815                 return NW_SUSPEND;
01816 }
01817 
01818 PUBLIC int
01819 tcp_read(fd, count)
01820 int fd;
01821 size_t count;
01822 {
01823         tcp_fd_t *tcp_fd;
01824         tcp_conn_t *tcp_conn;
01825 
01826         tcp_fd= &tcp_fd_table[fd];
01827 
01828         assert (tcp_fd->tf_flags & TFF_INUSE);
01829 
01830         if (!(tcp_fd->tf_flags & TFF_CONNECTED))
01831         {
01832                 reply_thr_put (tcp_fd, ENOTCONN, FALSE);
01833                 return NW_OK;
01834         }
01835         tcp_conn= tcp_fd->tf_conn;
01836 
01837         tcp_fd->tf_flags |= TFF_READ_IP;
01838         tcp_fd->tf_read_offset= 0;
01839         tcp_fd->tf_read_count= count;
01840 
01841         assert(tcp_conn->tc_busy == 0);
01842         tcp_conn->tc_busy++;
01843         tcp_fd_read(tcp_conn, 0);
01844         tcp_conn->tc_busy--;
01845         if (!(tcp_fd->tf_flags & TFF_READ_IP))
01846                 return NW_OK;
01847         else
01848                 return NW_SUSPEND;
01849 }
01850 
01851 /*
01852 tcp_restart_connect
01853 
01854 reply the success or failure of a connect to the user.
01855 */
01856 
01857 
01858 PUBLIC void tcp_restart_connect(tcp_conn)
01859 tcp_conn_t *tcp_conn;
01860 {
01861         tcp_fd_t *tcp_fd;
01862         int reply;
01863 
01864         assert(tcp_conn->tc_connInprogress);
01865         tcp_conn->tc_connInprogress= 0;
01866 
01867         tcp_fd= tcp_conn->tc_fd;
01868         assert(tcp_fd);
01869         if (tcp_fd->tf_flags & TFF_LISTENQ)
01870         {
01871                 /* Special code for listen queues */
01872                 assert(tcp_conn->tc_state != TCS_CLOSED);
01873 
01874                 /* Reply for select */
01875                 if ((tcp_fd->tf_flags & TFF_SEL_READ) &&
01876                         tcp_fd->tf_select_res)
01877                 {
01878                         tcp_fd->tf_flags &= ~TFF_SEL_READ;
01879                         tcp_fd->tf_select_res(tcp_fd->tf_srfd,
01880                                 SR_SELECT_READ);
01881                 }
01882 
01883                 /* Reply for acceptto */
01884                 if (tcp_fd->tf_flags & TFF_IOCTL_IP)
01885                         (void) tcp_acceptto(tcp_fd);
01886 
01887                 return;
01888         }
01889 
01890         if (tcp_conn->tc_state == TCS_CLOSED)
01891         {
01892                 reply= tcp_conn->tc_error;
01893                 assert(tcp_conn->tc_fd == tcp_fd);
01894                 tcp_fd->tf_conn= NULL;
01895                 tcp_conn->tc_fd= NULL;
01896                 tcp_fd->tf_error= reply;
01897         }
01898         else
01899         {
01900                 tcp_fd->tf_flags |= TFF_CONNECTED;
01901                 reply= NW_OK;
01902         }
01903 
01904         if (tcp_fd->tf_flags & TFF_CONNECTING)
01905         {
01906                 /* Special code for asynchronous connects */
01907                 tcp_fd->tf_flags &= ~TFF_CONNECTING;
01908 
01909                 /* Reply for select */
01910                 if ((tcp_fd->tf_flags & TFF_SEL_WRITE) &&
01911                         tcp_fd->tf_select_res)
01912                 {
01913                         tcp_fd->tf_flags &= ~TFF_SEL_WRITE;
01914                         tcp_fd->tf_select_res(tcp_fd->tf_srfd,
01915                                 SR_SELECT_WRITE);
01916                 }
01917 
01918                 return;
01919         }
01920 
01921         assert(tcp_fd->tf_flags & TFF_IOCTL_IP);
01922         assert(tcp_fd->tf_ioreq == NWIOTCPLISTEN ||
01923                 tcp_fd->tf_ioreq == NWIOTCPCONN);
01924 
01925         tcp_reply_ioctl (tcp_fd, reply);
01926 }
01927 
01928 /*
01929 tcp_close
01930 */
01931 
01932 PUBLIC void tcp_close(fd)
01933 int fd;
01934 {
01935         int i;
01936         tcp_fd_t *tcp_fd;
01937         tcp_conn_t *tcp_conn;
01938 
01939         tcp_fd= &tcp_fd_table[fd];
01940 
01941         assert (tcp_fd->tf_flags & TFF_INUSE);
01942         assert (!(tcp_fd->tf_flags &
01943                 (TFF_IOCTL_IP|TFF_READ_IP|TFF_WRITE_IP)));
01944 
01945         if (tcp_fd->tf_flags & TFF_LISTENQ)
01946         {
01947                 /* Special code for listen queues */
01948                 for (i= 0; i<TFL_LISTEN_MAX; i++)
01949                 {
01950                         tcp_conn= tcp_fd->tf_listenq[i];
01951                         if (!tcp_conn)
01952                                 continue;
01953 
01954                         tcp_fd->tf_listenq[i]= NULL;
01955                         assert(tcp_conn->tc_fd == tcp_fd);
01956                         tcp_conn->tc_fd= NULL;
01957 
01958                         if (tcp_conn->tc_connInprogress)
01959                         {
01960                                 tcp_conn->tc_connInprogress= 0;
01961                                 tcp_close_connection(tcp_conn, ENOCONN);
01962                                 continue;
01963                         }
01964 
01965                         tcp_shutdown (tcp_conn);
01966                         if (tcp_conn->tc_state == TCS_ESTABLISHED)
01967                                 tcp_conn->tc_state= TCS_CLOSING;
01968 
01969                         /* Set the retransmission timeout a bit smaller. */
01970                         tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_CLOSING;
01971 
01972                         /* If all data has been acknowledged, close the connection. */
01973                         if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
01974                                 tcp_close_connection(tcp_conn, ENOTCONN);
01975                 }
01976 
01977                 tcp_conn= tcp_fd->tf_conn;
01978                 assert(tcp_conn->tc_fd == tcp_fd);
01979                 assert (tcp_conn->tc_connInprogress);
01980                 tcp_conn->tc_connInprogress= 0;
01981                 tcp_conn->tc_fd= NULL;
01982                 tcp_fd->tf_conn= NULL;
01983                 tcp_close_connection(tcp_conn, ENOCONN);
01984         }
01985         for (i= 0; i<TFL_LISTEN_MAX; i++)
01986         {
01987                 assert(tcp_fd->tf_listenq[i] == NULL);
01988         }
01989 
01990         if (tcp_fd->tf_flags & TFF_CONNECTING)
01991         {
01992                 tcp_conn= tcp_fd->tf_conn;
01993                 assert(tcp_conn != NULL);
01994 
01995                 assert (tcp_conn->tc_connInprogress);
01996                 tcp_conn->tc_connInprogress= 0;
01997                 tcp_conn->tc_fd= NULL;
01998                 tcp_fd->tf_conn= NULL;
01999                 tcp_close_connection(tcp_conn, ENOCONN);
02000 
02001                 tcp_fd->tf_flags &= ~TFF_CONNECTING;
02002         }
02003 
02004         tcp_fd->tf_flags &= ~TFF_INUSE;
02005         if (!tcp_fd->tf_conn)
02006                 return;
02007 
02008 
02009         tcp_conn= tcp_fd->tf_conn;
02010         assert(tcp_conn->tc_fd == tcp_fd);
02011         tcp_conn->tc_fd= NULL;
02012 
02013         assert (!tcp_conn->tc_connInprogress);
02014 
02015         tcp_shutdown (tcp_conn);
02016         if (tcp_conn->tc_state == TCS_ESTABLISHED)
02017         {
02018                 tcp_conn->tc_state= TCS_CLOSING;
02019         }
02020 
02021         /* Set the retransmission timeout a bit smaller. */
02022         tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_CLOSING;
02023 
02024         /* If all data has been acknowledged, close the connection. */
02025         if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
02026                 tcp_close_connection(tcp_conn, ENOTCONN);
02027 }
02028 
02029 PUBLIC int tcp_cancel(fd, which_operation)
02030 int fd;
02031 int which_operation;
02032 {
02033         tcp_fd_t *tcp_fd;
02034         tcp_conn_t *tcp_conn;
02035 
02036         tcp_fd= &tcp_fd_table[fd];
02037 
02038         assert (tcp_fd->tf_flags & TFF_INUSE);
02039 
02040         tcp_conn= tcp_fd->tf_conn;
02041 
02042         switch (which_operation)
02043         {
02044         case SR_CANCEL_WRITE:
02045                 assert (tcp_fd->tf_flags & TFF_WRITE_IP);
02046                 tcp_fd->tf_flags &= ~TFF_WRITE_IP;
02047 
02048                 if (tcp_fd->tf_write_offset)
02049                         reply_thr_get (tcp_fd, tcp_fd->tf_write_offset, FALSE);
02050                 else
02051                         reply_thr_get (tcp_fd, EINTR, FALSE);
02052                 break;
02053         case SR_CANCEL_READ:
02054                 assert (tcp_fd->tf_flags & TFF_READ_IP);
02055                 tcp_fd->tf_flags &= ~TFF_READ_IP;
02056                 if (tcp_fd->tf_read_offset)
02057                         reply_thr_put (tcp_fd, tcp_fd->tf_read_offset, FALSE);
02058                 else
02059                         reply_thr_put (tcp_fd, EINTR, FALSE);
02060                 break;
02061         case SR_CANCEL_IOCTL:
02062 assert (tcp_fd->tf_flags & TFF_IOCTL_IP);
02063                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
02064 
02065                 if (tcp_fd->tf_flags & TFF_IOC_INIT_SP)
02066                 {
02067                         tcp_fd->tf_flags &= ~TFF_IOC_INIT_SP;
02068                         reply_thr_put (tcp_fd, EINTR, TRUE);
02069                         break;
02070                 }
02071 
02072                 switch (tcp_fd->tf_ioreq)
02073                 {
02074                 case NWIOGTCPCONF:
02075                         reply_thr_put (tcp_fd, EINTR, TRUE);
02076                         break;
02077                 case NWIOSTCPCONF:
02078                 case NWIOTCPSHUTDOWN:
02079                         reply_thr_get (tcp_fd, EINTR, TRUE);
02080                         break;
02081                 case NWIOTCPCONN:
02082                 case NWIOTCPLISTEN:
02083                         assert (tcp_conn->tc_connInprogress);
02084                         tcp_conn->tc_connInprogress= 0;
02085                         tcp_conn->tc_fd= NULL;
02086                         tcp_fd->tf_conn= NULL;
02087                         tcp_close_connection(tcp_conn, ENOCONN);
02088                         reply_thr_get (tcp_fd, EINTR, TRUE);
02089                         break;
02090                 default:
02091                         ip_warning(( "unknown ioctl inprogress: 0x%x",
02092                                 tcp_fd->tf_ioreq ));
02093                         reply_thr_get (tcp_fd, EINTR, TRUE);
02094                         break;
02095                 }
02096                 break;
02097         default:
02098                 ip_panic(( "unknown cancel request" ));
02099                 break;
02100         }
02101         return NW_OK;
02102 }
02103 
02104 /*
02105 tcp_connect
02106 */
02107 
02108 PRIVATE int tcp_connect(tcp_fd)
02109 tcp_fd_t *tcp_fd;
02110 {
02111         tcp_conn_t *tcp_conn;
02112         nwio_tcpcl_t *tcpcl;
02113         long nwtcl_flags;
02114         int r, do_asynch;
02115         acc_t *data;
02116 
02117         if (!(tcp_fd->tf_flags & TFF_CONF_SET))
02118         {
02119                 tcp_reply_ioctl(tcp_fd, EBADMODE);
02120                 return NW_OK;
02121         }
02122         assert (!(tcp_fd->tf_flags & TFF_CONNECTED) &&
02123                 !(tcp_fd->tf_flags & TFF_CONNECTING) &&
02124                 !(tcp_fd->tf_flags & TFF_LISTENQ));
02125         if ((tcp_fd->tf_tcpconf.nwtc_flags & (NWTC_SET_RA|NWTC_SET_RP))
02126                 != (NWTC_SET_RA|NWTC_SET_RP))
02127         {
02128                 tcp_reply_ioctl(tcp_fd, EBADMODE);
02129                 return NW_OK;
02130         }
02131 
02132         data= (*tcp_fd->tf_get_userdata) (tcp_fd->tf_srfd, 0,
02133                 sizeof(*tcpcl), TRUE);
02134         if (!data)
02135                 return EFAULT;
02136 
02137         data= bf_packIffLess(data, sizeof(*tcpcl));
02138         assert (data->acc_length == sizeof(*tcpcl));
02139         tcpcl= (nwio_tcpcl_t *)ptr2acc_data(data);
02140 
02141         nwtcl_flags= tcpcl->nwtcl_flags;
02142         bf_afree(data); data= NULL; tcpcl= NULL;
02143 
02144         if (nwtcl_flags == TCF_ASYNCH)
02145                 do_asynch= 1;
02146         else if (nwtcl_flags == TCF_DEFAULT)
02147                 do_asynch= 0;
02148         else
02149         {
02150                 tcp_reply_ioctl(tcp_fd, EINVAL);
02151                 return NW_OK;
02152         }
02153 
02154         assert(!tcp_fd->tf_conn);
02155         tcp_conn= find_conn_entry(tcp_fd->tf_tcpconf.nwtc_locport,
02156                 tcp_fd->tf_port->tp_ipaddr,
02157                 tcp_fd->tf_tcpconf.nwtc_remport,
02158                 tcp_fd->tf_tcpconf.nwtc_remaddr);
02159         if (tcp_conn)
02160         {
02161                 if (tcp_conn->tc_fd)
02162                 {
02163                         tcp_reply_ioctl(tcp_fd, EADDRINUSE);
02164                         return NW_OK;
02165                 }
02166         }
02167         else
02168         {
02169                 tcp_conn= find_empty_conn();
02170                 if (!tcp_conn)
02171                 {
02172                         tcp_reply_ioctl(tcp_fd, EAGAIN);
02173                         return NW_OK;
02174                 }
02175         }
02176         tcp_fd->tf_conn= tcp_conn;
02177 
02178         r= tcp_su4connect(tcp_fd);
02179         if (r == NW_SUSPEND && do_asynch)
02180         {
02181                 tcp_fd->tf_flags |= TFF_CONNECTING;
02182                 tcp_reply_ioctl(tcp_fd, EINPROGRESS);
02183                 r= NW_OK;
02184         }
02185         return r;
02186 }
02187 
02188 /*
02189 tcp_su4connect
02190 */
02191 
02192 PRIVATE int tcp_su4connect(tcp_fd)
02193 tcp_fd_t *tcp_fd;
02194 {
02195         tcp_conn_t *tcp_conn;
02196 
02197         tcp_conn= tcp_fd->tf_conn;
02198 
02199         tcp_conn->tc_locport= tcp_fd->tf_tcpconf.nwtc_locport;
02200         tcp_conn->tc_locaddr= tcp_fd->tf_port->tp_ipaddr;
02201 
02202         assert (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP);
02203         assert (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA);
02204         tcp_conn->tc_remport= tcp_fd->tf_tcpconf.nwtc_remport;
02205         tcp_conn->tc_remaddr= tcp_fd->tf_tcpconf.nwtc_remaddr;
02206 
02207         tcp_setup_conn(tcp_fd->tf_port, tcp_conn);
02208 
02209         tcp_conn->tc_fd= tcp_fd;
02210         tcp_conn->tc_connInprogress= 1;
02211         tcp_conn->tc_orglisten= FALSE;
02212         tcp_conn->tc_state= TCS_SYN_SENT;
02213         tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_CONNECT;
02214 
02215         /* Start the timer (if necessary) */
02216         tcp_set_send_timer(tcp_conn);
02217 
02218         tcp_conn_write(tcp_conn, 0);
02219 
02220         if (tcp_conn->tc_connInprogress)
02221                 return NW_SUSPEND;
02222         else
02223                 return NW_OK;
02224 }
02225 
02226 
02227 /*
02228 tcp_listen
02229 */
02230 
02231 PRIVATE int tcp_listen(tcp_fd, do_listenq)
02232 tcp_fd_t *tcp_fd;
02233 int do_listenq;
02234 {
02235         tcp_conn_t *tcp_conn;
02236 
02237         if (!(tcp_fd->tf_flags & TFF_CONF_SET))
02238         {
02239                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
02240                 reply_thr_get(tcp_fd, EBADMODE, TRUE);
02241                 return NW_OK;
02242         }
02243         assert (!(tcp_fd->tf_flags & TFF_CONNECTED) &&
02244                 !(tcp_fd->tf_flags & TFF_CONNECTING) &&
02245                 !(tcp_fd->tf_flags & TFF_LISTENQ));
02246         tcp_conn= tcp_fd->tf_conn;
02247         assert(!tcp_conn);
02248 
02249         if ((tcp_fd->tf_tcpconf.nwtc_flags & (NWTC_SET_RA|NWTC_SET_RP))
02250                 == (NWTC_SET_RA|NWTC_SET_RP))
02251         {
02252                 tcp_conn= find_conn_entry(
02253                         tcp_fd->tf_tcpconf.nwtc_locport,
02254                         tcp_fd->tf_port->tp_ipaddr,
02255                         tcp_fd->tf_tcpconf.nwtc_remport,
02256                         tcp_fd->tf_tcpconf.nwtc_remaddr);
02257                 if (tcp_conn)
02258                 {
02259                         if (tcp_conn->tc_fd)
02260                         {
02261                                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
02262                                 reply_thr_get (tcp_fd, EADDRINUSE, TRUE);
02263                                 return NW_OK;
02264                         }
02265                         tcp_fd->tf_conn= tcp_conn;
02266                         return tcp_su4listen(tcp_fd, tcp_conn, do_listenq);
02267                 }
02268         }
02269         tcp_conn= find_empty_conn();
02270         if (!tcp_conn)
02271         {
02272                 tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
02273                 reply_thr_get (tcp_fd, EAGAIN, TRUE);
02274                 return NW_OK;
02275         }
02276         tcp_fd->tf_conn= tcp_conn;
02277         return tcp_su4listen(tcp_fd, tcp_conn, do_listenq);
02278 }
02279 
02280 /*
02281 tcp_acceptto
02282 */
02283 
02284 PRIVATE int tcp_acceptto(tcp_fd)
02285 tcp_fd_t *tcp_fd;
02286 {
02287         int i, dst_nr;
02288         tcp_fd_t *dst_fd;
02289         tcp_conn_t *tcp_conn;
02290         tcp_cookie_t *cookiep;
02291         acc_t *data;
02292         tcp_cookie_t cookie;
02293 
02294         if (!(tcp_fd->tf_flags & TFF_LISTENQ))
02295         {
02296                 tcp_reply_ioctl(tcp_fd, EINVAL);
02297                 return NW_OK;
02298         }
02299         for (i= 0; i<TFL_LISTEN_MAX; i++)
02300         {
02301                 tcp_conn= tcp_fd->tf_listenq[i];
02302                 if (tcp_conn && !tcp_conn->tc_connInprogress)
02303                         break;
02304         }
02305         if (i >= TFL_LISTEN_MAX)
02306         {
02307                 /* Nothing, suspend caller */
02308                 return NW_SUSPEND;
02309         }
02310 
02311         data= (*tcp_fd->tf_get_userdata) (tcp_fd->tf_srfd, 0,
02312                 sizeof(*cookiep), TRUE);
02313         if (!data)
02314                 return EFAULT;
02315 
02316         data= bf_packIffLess(data, sizeof(*cookiep));
02317         cookiep= (tcp_cookie_t *)ptr2acc_data(data);
02318         cookie= *cookiep;
02319 
02320         bf_afree(data); data= NULL;
02321 
02322         dst_nr= cookie.tc_ref;
02323         if (dst_nr < 0 || dst_nr >= TCP_FD_NR)
02324         {
02325                 printf("tcp_acceptto: bad fd %d\n", dst_nr);
02326                 tcp_reply_ioctl(tcp_fd, EINVAL);
02327                 return NW_OK;
02328         }
02329         dst_fd= &tcp_fd_table[dst_nr];
02330         if (!(dst_fd->tf_flags & TFF_INUSE) ||
02331                 (dst_fd->tf_flags & (TFF_READ_IP|TFF_WRITE_IP|TFF_IOCTL_IP)) ||
02332                 dst_fd->tf_conn != NULL ||
02333                 !(dst_fd->tf_flags & TFF_COOKIE))
02334         {
02335                 printf("tcp_acceptto: bad flags 0x%x or conn %p for fd %d\n",
02336                         dst_fd->tf_flags, dst_fd->tf_conn, dst_nr);
02337                 tcp_reply_ioctl(tcp_fd, EINVAL);
02338                 return NW_OK;
02339         }
02340         if (memcmp(&cookie, &dst_fd->tf_cookie, sizeof(cookie)) != 0)
02341         {
02342                 printf("tcp_acceptto: bad cookie\n");
02343                 return NW_OK;
02344         }
02345 
02346         /* Move connection */
02347         tcp_fd->tf_listenq[i]= NULL;
02348         tcp_conn->tc_fd= dst_fd;
02349         dst_fd->tf_conn= tcp_conn;
02350         dst_fd->tf_flags |= TFF_CONNECTED;
02351 
02352         tcp_reply_ioctl(tcp_fd, NW_OK);
02353         return NW_OK;
02354 }
02355 
02356 
02357 PRIVATE void tcp_buffree (priority)
02358 int priority;
02359 {
02360         int i;
02361         tcp_conn_t *tcp_conn;
02362 
02363         if (priority == TCP_PRI_FRAG2SEND)
02364         {
02365                 for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
02366                         tcp_conn++)
02367                 {
02368                         if (!(tcp_conn->tc_flags & TCF_INUSE))
02369                                 continue;
02370                         if (!tcp_conn->tc_frag2send)
02371                                 continue;
02372                         if (tcp_conn->tc_busy)
02373                                 continue;
02374                         bf_afree(tcp_conn->tc_frag2send);
02375                         tcp_conn->tc_frag2send= 0;
02376                 }
02377         }
02378 
02379         if (priority == TCP_PRI_CONN_EXTRA)
02380         {
02381                 for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
02382                         tcp_conn++)
02383                 {
02384                         if (!(tcp_conn->tc_flags & TCF_INUSE))
02385                                 continue;
02386                         if (tcp_conn->tc_busy)
02387                                 continue;
02388                         if (tcp_conn->tc_adv_data)
02389                         {
02390                                 bf_afree(tcp_conn->tc_adv_data);
02391                                 tcp_conn->tc_adv_data= NULL;
02392                         }
02393                 }
02394         }
02395 
02396         if (priority == TCP_PRI_CONNwoUSER)
02397         {
02398                 for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
02399                         tcp_conn++)
02400                 {
02401                         if (!(tcp_conn->tc_flags & TCF_INUSE))
02402                                 continue;
02403                         if (tcp_conn->tc_busy)
02404                                 continue;
02405                         if (tcp_conn->tc_fd)
02406                                 continue;
02407                         if (tcp_conn->tc_state == TCS_CLOSED)
02408                                 continue;
02409                         if (tcp_conn->tc_rcvd_data == NULL &&
02410                                 tcp_conn->tc_send_data == NULL)
02411                         {
02412                                 continue;
02413                         }
02414                         tcp_close_connection (tcp_conn, EOUTOFBUFS);
02415                 }
02416         }
02417 
02418         if (priority == TCP_PRI_CONN_INUSE)
02419         {
02420                 for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
02421                         tcp_conn++)
02422                 {
02423                         if (!(tcp_conn->tc_flags & TCF_INUSE))
02424                                 continue;
02425                         if (tcp_conn->tc_busy)
02426                                 continue;
02427                         if (tcp_conn->tc_state == TCS_CLOSED)
02428                                 continue;
02429                         if (tcp_conn->tc_rcvd_data == NULL &&
02430                                 tcp_conn->tc_send_data == NULL)
02431                         {
02432                                 continue;
02433                         }
02434                         tcp_close_connection (tcp_conn, EOUTOFBUFS);
02435                 }
02436         }
02437 }
02438 
02439 #ifdef BUF_CONSISTENCY_CHECK
02440 PRIVATE void tcp_bufcheck()
02441 {
02442         int i;
02443         tcp_conn_t *tcp_conn;
02444         tcp_port_t *tcp_port;
02445 
02446         for (i= 0, tcp_port= tcp_port_table; i<tcp_conf_nr; i++, tcp_port++)
02447         {
02448                 if (tcp_port->tp_pack)
02449                         bf_check_acc(tcp_port->tp_pack);
02450         }
02451         for (i= 0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++, tcp_conn++)
02452         {
02453                 assert(!tcp_conn->tc_busy);
02454                 if (tcp_conn->tc_rcvd_data)
02455                         bf_check_acc(tcp_conn->tc_rcvd_data);
02456                 if (tcp_conn->tc_adv_data)
02457                         bf_check_acc(tcp_conn->tc_adv_data);
02458                 if (tcp_conn->tc_send_data)
02459                         bf_check_acc(tcp_conn->tc_send_data);
02460                 if (tcp_conn->tc_remipopt)
02461                         bf_check_acc(tcp_conn->tc_remipopt);
02462                 if (tcp_conn->tc_tcpopt)
02463                         bf_check_acc(tcp_conn->tc_tcpopt);
02464                 if (tcp_conn->tc_frag2send)
02465                         bf_check_acc(tcp_conn->tc_frag2send);
02466         }
02467 }
02468 #endif
02469 
02470 PUBLIC void tcp_notreach(tcp_conn)
02471 tcp_conn_t *tcp_conn;
02472 {
02473         int new_ttl;
02474 
02475         new_ttl= tcp_conn->tc_ttl;
02476         if (new_ttl == IP_MAX_TTL)
02477         {
02478                 if (tcp_conn->tc_state == TCS_SYN_SENT)
02479                         tcp_close_connection(tcp_conn, EDSTNOTRCH);
02480                 return;
02481         }
02482         else if (new_ttl < TCP_DEF_TTL_NEXT)
02483                 new_ttl= TCP_DEF_TTL_NEXT;
02484         else
02485         {
02486                 new_ttl *= 2;
02487                 if (new_ttl> IP_MAX_TTL)
02488                         new_ttl= IP_MAX_TTL;
02489         }
02490         tcp_conn->tc_ttl= new_ttl;
02491         tcp_conn->tc_stt= 0;
02492         tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
02493         tcp_conn_write(tcp_conn, 1);
02494 }
02495 
02496 FORWARD u32_t mtu_table[]=
02497 {       /* From RFC-1191 */
02498 /*      Plateau    MTU    Comments                      Reference       */
02499 /*      ------     ---    --------                      ---------       */
02500 /*                65535  Official maximum MTU          RFC 791          */
02501 /*                65535  Hyperchannel                  RFC 1044         */
02502         65535,
02503         32000,    /*     Just in case                                   */
02504 /*                17914  16Mb IBM Token Ring           ref. [6]         */
02505         17914,
02506 /*                8166   IEEE 802.4                    RFC 1042         */
02507         8166,
02508 /*                4464   IEEE 802.5 (4Mb max)          RFC 1042         */
02509 /*                4352   FDDI (Revised)                RFC 1188         */
02510         4352, /* (1%) */
02511 /*                2048   Wideband Network              RFC 907          */
02512 /*                2002   IEEE 802.5 (4Mb recommended)  RFC 1042         */
02513         2002, /* (2%) */
02514 /*                1536   Exp. Ethernet Nets            RFC 895          */
02515 /*                1500   Ethernet Networks             RFC 894          */
02516 /*                1500   Point-to-Point (default)      RFC 1134         */
02517 /*                1492   IEEE 802.3                    RFC 1042         */
02518         1492, /* (3%) */
02519 /*                1006   SLIP                          RFC 1055         */
02520 /*                1006   ARPANET                       BBN 1822         */
02521         1006,
02522 /*                576    X.25 Networks                 RFC 877          */
02523 /*                544    DEC IP Portal                 ref. [10]        */
02524 /*                512    NETBIOS                       RFC 1088         */
02525 /*                508    IEEE 802/Source-Rt Bridge     RFC 1042         */
02526 /*                508    ARCNET                        RFC 1051         */
02527         508, /* (13%) */
02528 /*                296    Point-to-Point (low delay)    RFC 1144         */
02529         296,
02530         68,       /*     Official minimum MTU          RFC 791          */
02531         0,        /*     End of list                                    */
02532 };
02533 
02534 PUBLIC void tcp_mtu_exceeded(tcp_conn)
02535 tcp_conn_t *tcp_conn;
02536 {
02537         u16_t mtu;
02538         int i;
02539         clock_t curr_time;
02540 
02541         if (!(tcp_conn->tc_flags & TCF_PMTU))
02542         {
02543                 /* Strange, got MTU exceeded but DF is not set. Ignore
02544                  * the error. If the problem persists, the connection will
02545                  * time-out.
02546                  */
02547                 return;
02548         }
02549         curr_time= get_time();
02550 
02551         /* We get here in cases. Either were are trying to find an MTU 
02552          * that works at all, or we are trying see how far we can increase
02553          * the current MTU. If the last change to the MTU was a long time 
02554          * ago, we assume the second case. 
02555          */
02556         if (curr_time >= tcp_conn->tc_mtutim + TCP_PMTU_INCR_IV)
02557         {
02558                 mtu= tcp_conn->tc_mtu;
02559                 mtu -= mtu/TCP_PMTU_INCR_FRAC;
02560                 tcp_conn->tc_mtu= mtu;
02561                 tcp_conn->tc_mtutim= curr_time;
02562                 DBLOCK(1, printf(
02563                         "tcp_mtu_exceeded: new (lowered) mtu %d for conn %d\n",
02564                         mtu, tcp_conn-tcp_conn_table));
02565                 tcp_conn->tc_stt= 0;
02566                 tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
02567                 tcp_conn_write(tcp_conn, 1);
02568                 return;
02569         }
02570 
02571         tcp_conn->tc_mtutim= curr_time;
02572         mtu= tcp_conn->tc_mtu;
02573         for (i= 0; mtu_table[i] >= mtu; i++)
02574                 ;       /* Nothing to do */
02575         mtu= mtu_table[i];
02576         if (mtu >= TCP_MIN_PATH_MTU)
02577         {
02578                 tcp_conn->tc_mtu= mtu;
02579         }
02580         else
02581         {
02582                 /* Small MTUs can be used for denial-of-service attacks.
02583                  * Switch-off PMTU if the MTU becomes too small.
02584                  */
02585                 tcp_conn->tc_flags &= ~TCF_PMTU;
02586                 tcp_conn->tc_mtu= TCP_MIN_PATH_MTU;
02587                 DBLOCK(1, printf(
02588                         "tcp_mtu_exceeded: clearing TCF_PMTU for conn %d\n",
02589                         tcp_conn-tcp_conn_table););
02590 
02591         }
02592         DBLOCK(1, printf("tcp_mtu_exceeded: new mtu %d for conn %d\n",
02593                 mtu, tcp_conn-tcp_conn_table););
02594         tcp_conn->tc_stt= 0;
02595         tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
02596         tcp_conn_write(tcp_conn, 1);
02597 }
02598 
02599 PUBLIC void tcp_mtu_incr(tcp_conn)
02600 tcp_conn_t *tcp_conn;
02601 {
02602         clock_t curr_time;
02603         u32_t mtu;
02604 
02605         assert(tcp_conn->tc_mtu < tcp_conn->tc_max_mtu);
02606         if (!(tcp_conn->tc_flags & TCF_PMTU))
02607         {
02608                 /* Use a much longer time-out for retrying PMTU discovery
02609                  * after is has been disabled. Note that PMTU discovery
02610                  * can be disabled during a short loss of connectivity.
02611                  */
02612                 curr_time= get_time();
02613                 if (curr_time > tcp_conn->tc_mtutim+TCP_PMTU_EN_IV)
02614                 {
02615                         tcp_conn->tc_flags |= TCF_PMTU;
02616                         DBLOCK(1, printf(
02617                                 "tcp_mtu_incr: setting TCF_PMTU for conn %d\n",
02618                                 tcp_conn-tcp_conn_table););
02619                 }
02620                 return;
02621         }
02622 
02623         mtu= tcp_conn->tc_mtu;
02624         mtu += mtu/TCP_PMTU_INCR_FRAC;
02625         if (mtu > tcp_conn->tc_max_mtu)
02626                 mtu= tcp_conn->tc_max_mtu;
02627         tcp_conn->tc_mtu= mtu;
02628         DBLOCK(0x1, printf("tcp_mtu_incr: new mtu %ld for conn %d\n",
02629                 mtu, tcp_conn-tcp_conn_table););
02630 }
02631 
02632 /*
02633 tcp_setup_conn
02634 */
02635 
02636 PRIVATE void tcp_setup_conn(tcp_port, tcp_conn)
02637 tcp_port_t *tcp_port;
02638 tcp_conn_t *tcp_conn;
02639 {
02640         u16_t mss;
02641 
02642         assert(!tcp_conn->tc_connInprogress);
02643         tcp_conn->tc_port= tcp_port;
02644         if (tcp_conn->tc_flags & TCF_INUSE)
02645         {
02646                 assert (tcp_conn->tc_state == TCS_CLOSED);
02647                 assert (!tcp_conn->tc_send_data);
02648                 if (tcp_conn->tc_senddis < get_time())
02649                         tcp_conn->tc_ISS= 0;
02650         }
02651         else
02652         {
02653                 assert(!tcp_conn->tc_busy);
02654                 tcp_conn->tc_senddis= 0;
02655                 tcp_conn->tc_ISS= 0;
02656                 tcp_conn->tc_tos= TCP_DEF_TOS;
02657                 tcp_conn->tc_ttl= TCP_DEF_TTL;
02658                 tcp_conn->tc_rcv_wnd= TCP_MAX_RCV_WND_SIZE;
02659                 tcp_conn->tc_fd= NULL;
02660         }
02661         if (!tcp_conn->tc_ISS)
02662         {
02663                 tcp_conn->tc_ISS= tcp_rand32();
02664         }
02665         tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
02666         tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
02667         tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS+1;
02668         tcp_conn->tc_SND_UP= tcp_conn->tc_ISS;
02669         tcp_conn->tc_SND_PSH= tcp_conn->tc_ISS+1;
02670         tcp_conn->tc_IRS= 0;
02671         tcp_conn->tc_RCV_LO= tcp_conn->tc_IRS;
02672         tcp_conn->tc_RCV_NXT= tcp_conn->tc_IRS;
02673         tcp_conn->tc_RCV_HI= tcp_conn->tc_IRS;
02674         tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS;
02675 
02676         assert(tcp_conn->tc_rcvd_data == NULL);
02677         assert(tcp_conn->tc_adv_data == NULL);
02678         assert(tcp_conn->tc_send_data == NULL);
02679 
02680         tcp_conn->tc_ka_time= TCP_DEF_KEEPALIVE;
02681 
02682         tcp_conn->tc_remipopt= NULL;
02683         tcp_conn->tc_tcpopt= NULL;
02684 
02685         assert(tcp_conn->tc_frag2send == NULL);
02686 
02687         tcp_conn->tc_stt= 0;
02688         tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
02689         tcp_conn->tc_0wnd_to= 0;
02690         tcp_conn->tc_artt= TCP_DEF_RTT*TCP_RTT_SCALE;
02691         tcp_conn->tc_drtt= 0;
02692         tcp_conn->tc_rtt= TCP_DEF_RTT;
02693         tcp_conn->tc_max_mtu= tcp_conn->tc_port->tp_mtu;
02694         tcp_conn->tc_mtu= tcp_conn->tc_max_mtu;
02695         tcp_conn->tc_mtutim= 0;
02696         tcp_conn->tc_error= NW_OK;
02697         mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
02698         tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA + 2*mss;
02699         tcp_conn->tc_snd_cthresh= TCP_MAX_SND_WND_SIZE;
02700         tcp_conn->tc_snd_cinc=
02701                 (long)TCP_DEF_MSS*TCP_DEF_MSS/TCP_MAX_SND_WND_SIZE+1;
02702         tcp_conn->tc_snd_wnd= TCP_MAX_SND_WND_SIZE;
02703         tcp_conn->tc_rt_time= 0;
02704         tcp_conn->tc_rt_seq= 0;
02705         tcp_conn->tc_rt_threshold= tcp_conn->tc_ISS;
02706         tcp_conn->tc_flags= TCF_INUSE;
02707         tcp_conn->tc_flags |= TCF_PMTU;
02708 
02709         clck_untimer(&tcp_conn->tc_transmit_timer);
02710         tcp_conn->tc_transmit_seq= 0;
02711 }
02712 
02713 PRIVATE u32_t tcp_rand32()
02714 {
02715         u8_t bits[RAND256_BUFSIZE];
02716 
02717         rand256(bits);
02718         return bits[0] | (bits[1] << 8) | (bits[2] << 16) | (bits[3] << 24);
02719 }
02720 
02721 /*
02722  * $PchId: tcp.c,v 1.34 2005/06/28 14:20:27 philip Exp $
02723  */

Generated on Fri Apr 14 22:57:31 2006 for minix by  doxygen 1.4.6