[9] | 1 | /*
|
---|
| 2 | tcp.c
|
---|
| 3 |
|
---|
| 4 | Copyright 1995 Philip Homburg
|
---|
| 5 | */
|
---|
| 6 |
|
---|
| 7 | #include "inet.h"
|
---|
| 8 | #include "buf.h"
|
---|
| 9 | #include "clock.h"
|
---|
| 10 | #include "event.h"
|
---|
| 11 | #include "type.h"
|
---|
| 12 |
|
---|
| 13 | #include "io.h"
|
---|
| 14 | #include "ip.h"
|
---|
| 15 | #include "sr.h"
|
---|
| 16 | #include "assert.h"
|
---|
| 17 | #include "rand256.h"
|
---|
| 18 | #include "tcp.h"
|
---|
| 19 | #include "tcp_int.h"
|
---|
| 20 |
|
---|
| 21 | THIS_FILE
|
---|
| 22 |
|
---|
| 23 | #define NOT_IMPLEMENTED 0
|
---|
| 24 |
|
---|
| 25 | PUBLIC tcp_port_t *tcp_port_table;
|
---|
| 26 | PUBLIC tcp_fd_t tcp_fd_table[TCP_FD_NR];
|
---|
| 27 | PUBLIC tcp_conn_t tcp_conn_table[TCP_CONN_NR];
|
---|
| 28 | PUBLIC sr_cancel_t tcp_cancel_f;
|
---|
| 29 |
|
---|
| 30 | FORWARD void tcp_main ARGS(( tcp_port_t *port ));
|
---|
| 31 | FORWARD int tcp_select ARGS(( int fd, unsigned operations ));
|
---|
| 32 | FORWARD acc_t *tcp_get_data ARGS(( int fd, size_t offset,
|
---|
| 33 | size_t count, int for_ioctl ));
|
---|
| 34 | FORWARD int tcp_put_data ARGS(( int fd, size_t offset,
|
---|
| 35 | acc_t *data, int for_ioctl ));
|
---|
| 36 | FORWARD void tcp_put_pkt ARGS(( int fd, acc_t *data, size_t datalen ));
|
---|
| 37 | FORWARD void read_ip_packets ARGS(( tcp_port_t *port ));
|
---|
| 38 | FORWARD int tcp_setconf ARGS(( tcp_fd_t *tcp_fd ));
|
---|
| 39 | FORWARD int tcp_setopt ARGS(( tcp_fd_t *tcp_fd ));
|
---|
| 40 | FORWARD int tcp_connect ARGS(( tcp_fd_t *tcp_fd ));
|
---|
| 41 | FORWARD int tcp_listen ARGS(( tcp_fd_t *tcp_fd, int do_listenq ));
|
---|
| 42 | FORWARD int tcp_acceptto ARGS(( tcp_fd_t *tcp_fd ));
|
---|
| 43 | FORWARD tcpport_t find_unused_port ARGS(( int fd ));
|
---|
| 44 | FORWARD int is_unused_port ARGS(( Tcpport_t port ));
|
---|
| 45 | FORWARD int reply_thr_put ARGS(( tcp_fd_t *tcp_fd, int reply,
|
---|
| 46 | int for_ioctl ));
|
---|
| 47 | FORWARD void reply_thr_get ARGS(( tcp_fd_t *tcp_fd, int reply,
|
---|
| 48 | int for_ioctl ));
|
---|
| 49 | FORWARD tcp_conn_t *find_conn_entry ARGS(( Tcpport_t locport,
|
---|
| 50 | ipaddr_t locaddr, Tcpport_t remport, ipaddr_t readaddr ));
|
---|
| 51 | FORWARD tcp_conn_t *find_empty_conn ARGS(( void ));
|
---|
| 52 | FORWARD tcp_conn_t *find_best_conn ARGS(( ip_hdr_t *ip_hdr,
|
---|
| 53 | tcp_hdr_t *tcp_hdr ));
|
---|
| 54 | FORWARD tcp_conn_t *new_conn_for_queue ARGS(( tcp_fd_t *tcp_fd ));
|
---|
| 55 | FORWARD int maybe_listen ARGS(( ipaddr_t locaddr, Tcpport_t locport,
|
---|
| 56 | ipaddr_t remaddr, Tcpport_t remport ));
|
---|
| 57 | FORWARD int tcp_su4connect ARGS(( tcp_fd_t *tcp_fd ));
|
---|
| 58 | FORWARD void tcp_buffree ARGS(( int priority ));
|
---|
| 59 | #ifdef BUF_CONSISTENCY_CHECK
|
---|
| 60 | FORWARD void tcp_bufcheck ARGS(( void ));
|
---|
| 61 | #endif
|
---|
| 62 | FORWARD void tcp_setup_conn ARGS(( tcp_port_t *tcp_port,
|
---|
| 63 | tcp_conn_t *tcp_conn ));
|
---|
| 64 | FORWARD u32_t tcp_rand32 ARGS(( void ));
|
---|
| 65 |
|
---|
| 66 | PUBLIC void tcp_prep()
|
---|
| 67 | {
|
---|
| 68 | tcp_port_table= alloc(tcp_conf_nr * sizeof(tcp_port_table[0]));
|
---|
| 69 | }
|
---|
| 70 |
|
---|
| 71 | PUBLIC void tcp_init()
|
---|
| 72 | {
|
---|
| 73 | int i, j, k, ifno;
|
---|
| 74 | tcp_fd_t *tcp_fd;
|
---|
| 75 | tcp_port_t *tcp_port;
|
---|
| 76 | tcp_conn_t *tcp_conn;
|
---|
| 77 |
|
---|
| 78 | assert (BUF_S >= sizeof(struct nwio_ipopt));
|
---|
| 79 | assert (BUF_S >= sizeof(struct nwio_ipconf));
|
---|
| 80 | assert (BUF_S >= sizeof(struct nwio_tcpconf));
|
---|
| 81 | assert (BUF_S >= IP_MAX_HDR_SIZE + TCP_MAX_HDR_SIZE);
|
---|
| 82 |
|
---|
| 83 | for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++, tcp_fd++)
|
---|
| 84 | {
|
---|
| 85 | tcp_fd->tf_flags= TFF_EMPTY;
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
|
---|
| 89 | tcp_fd++)
|
---|
| 90 | {
|
---|
| 91 | tcp_conn->tc_flags= TCF_EMPTY;
|
---|
| 92 | tcp_conn->tc_busy= 0;
|
---|
| 93 | }
|
---|
| 94 |
|
---|
| 95 | #ifndef BUF_CONSISTENCY_CHECK
|
---|
| 96 | bf_logon(tcp_buffree);
|
---|
| 97 | #else
|
---|
| 98 | bf_logon(tcp_buffree, tcp_bufcheck);
|
---|
| 99 | #endif
|
---|
| 100 |
|
---|
| 101 | for (i=0, tcp_port= tcp_port_table; i<tcp_conf_nr; i++, tcp_port++)
|
---|
| 102 | {
|
---|
| 103 | tcp_port->tp_ipdev= tcp_conf[i].tc_port;
|
---|
| 104 |
|
---|
| 105 | tcp_port->tp_flags= TPF_EMPTY;
|
---|
| 106 | tcp_port->tp_state= TPS_EMPTY;
|
---|
| 107 | tcp_port->tp_snd_head= NULL;
|
---|
| 108 | tcp_port->tp_snd_tail= NULL;
|
---|
| 109 | ev_init(&tcp_port->tp_snd_event);
|
---|
| 110 | for (j= 0; j<TCP_CONN_HASH_NR; j++)
|
---|
| 111 | {
|
---|
| 112 | for (k= 0; k<4; k++)
|
---|
| 113 | {
|
---|
| 114 | tcp_port->tp_conn_hash[j][k]=
|
---|
| 115 | &tcp_conn_table[0];
|
---|
| 116 | }
|
---|
| 117 | }
|
---|
| 118 |
|
---|
| 119 | ifno= ip_conf[tcp_port->tp_ipdev].ic_ifno;
|
---|
| 120 | sr_add_minor(if2minor(ifno, TCP_DEV_OFF),
|
---|
| 121 | i, tcp_open, tcp_close, tcp_read,
|
---|
| 122 | tcp_write, tcp_ioctl, tcp_cancel, tcp_select);
|
---|
| 123 |
|
---|
| 124 | tcp_main(tcp_port);
|
---|
| 125 | }
|
---|
| 126 | tcp_cancel_f= tcp_cancel;
|
---|
| 127 | }
|
---|
| 128 |
|
---|
| 129 | PRIVATE void tcp_main(tcp_port)
|
---|
| 130 | tcp_port_t *tcp_port;
|
---|
| 131 | {
|
---|
| 132 | int result, i;
|
---|
| 133 | tcp_conn_t *tcp_conn;
|
---|
| 134 | tcp_fd_t *tcp_fd;
|
---|
| 135 |
|
---|
| 136 | switch (tcp_port->tp_state)
|
---|
| 137 | {
|
---|
| 138 | case TPS_EMPTY:
|
---|
| 139 | tcp_port->tp_state= TPS_SETPROTO;
|
---|
| 140 | tcp_port->tp_ipfd= ip_open(tcp_port->tp_ipdev,
|
---|
| 141 | tcp_port->tp_ipdev, tcp_get_data,
|
---|
| 142 | tcp_put_data, tcp_put_pkt, 0 /* no select_res */);
|
---|
| 143 | if (tcp_port->tp_ipfd < 0)
|
---|
| 144 | {
|
---|
| 145 | tcp_port->tp_state= TPS_ERROR;
|
---|
| 146 | DBLOCK(1, printf("%s, %d: unable to open ip port\n",
|
---|
| 147 | __FILE__, __LINE__));
|
---|
| 148 | return;
|
---|
| 149 | }
|
---|
| 150 |
|
---|
| 151 | result= ip_ioctl(tcp_port->tp_ipfd, NWIOSIPOPT);
|
---|
| 152 | if (result == NW_SUSPEND)
|
---|
| 153 | tcp_port->tp_flags |= TPF_SUSPEND;
|
---|
| 154 | if (result < 0)
|
---|
| 155 | {
|
---|
| 156 | return;
|
---|
| 157 | }
|
---|
| 158 | if (tcp_port->tp_state != TPS_GETCONF)
|
---|
| 159 | return;
|
---|
| 160 | /* drops through */
|
---|
| 161 | case TPS_GETCONF:
|
---|
| 162 | tcp_port->tp_flags &= ~TPF_SUSPEND;
|
---|
| 163 |
|
---|
| 164 | result= ip_ioctl(tcp_port->tp_ipfd, NWIOGIPCONF);
|
---|
| 165 | if (result == NW_SUSPEND)
|
---|
| 166 | tcp_port->tp_flags |= TPF_SUSPEND;
|
---|
| 167 | if (result < 0)
|
---|
| 168 | {
|
---|
| 169 | return;
|
---|
| 170 | }
|
---|
| 171 | if (tcp_port->tp_state != TPS_MAIN)
|
---|
| 172 | return;
|
---|
| 173 | /* drops through */
|
---|
| 174 | case TPS_MAIN:
|
---|
| 175 | tcp_port->tp_flags &= ~TPF_SUSPEND;
|
---|
| 176 | tcp_port->tp_pack= 0;
|
---|
| 177 |
|
---|
| 178 | tcp_conn= &tcp_conn_table[tcp_port->tp_ipdev];
|
---|
| 179 | tcp_conn->tc_flags= TCF_INUSE;
|
---|
| 180 | assert(!tcp_conn->tc_busy);
|
---|
| 181 | tcp_conn->tc_locport= 0;
|
---|
| 182 | tcp_conn->tc_locaddr= tcp_port->tp_ipaddr;
|
---|
| 183 | tcp_conn->tc_remport= 0;
|
---|
| 184 | tcp_conn->tc_remaddr= 0;
|
---|
| 185 | tcp_conn->tc_state= TCS_CLOSED;
|
---|
| 186 | tcp_conn->tc_fd= 0;
|
---|
| 187 | tcp_conn->tc_connInprogress= 0;
|
---|
| 188 | tcp_conn->tc_orglisten= FALSE;
|
---|
| 189 | tcp_conn->tc_senddis= 0;
|
---|
| 190 | tcp_conn->tc_ISS= 0;
|
---|
| 191 | tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
|
---|
| 192 | tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
|
---|
| 193 | tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS;
|
---|
| 194 | tcp_conn->tc_SND_UP= tcp_conn->tc_ISS;
|
---|
| 195 | tcp_conn->tc_IRS= 0;
|
---|
| 196 | tcp_conn->tc_RCV_LO= tcp_conn->tc_IRS;
|
---|
| 197 | tcp_conn->tc_RCV_NXT= tcp_conn->tc_IRS;
|
---|
| 198 | tcp_conn->tc_RCV_HI= tcp_conn->tc_IRS;
|
---|
| 199 | tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS;
|
---|
| 200 | tcp_conn->tc_port= tcp_port;
|
---|
| 201 | tcp_conn->tc_rcvd_data= NULL;
|
---|
| 202 | tcp_conn->tc_adv_data= NULL;
|
---|
| 203 | tcp_conn->tc_send_data= 0;
|
---|
| 204 | tcp_conn->tc_remipopt= NULL;
|
---|
| 205 | tcp_conn->tc_tcpopt= NULL;
|
---|
| 206 | tcp_conn->tc_frag2send= 0;
|
---|
| 207 | tcp_conn->tc_tos= TCP_DEF_TOS;
|
---|
| 208 | tcp_conn->tc_ttl= IP_MAX_TTL;
|
---|
| 209 | tcp_conn->tc_rcv_wnd= TCP_MAX_RCV_WND_SIZE;
|
---|
| 210 | tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
|
---|
| 211 | tcp_conn->tc_stt= 0;
|
---|
| 212 | tcp_conn->tc_0wnd_to= 0;
|
---|
| 213 | tcp_conn->tc_artt= TCP_DEF_RTT*TCP_RTT_SCALE;
|
---|
| 214 | tcp_conn->tc_drtt= 0;
|
---|
| 215 | tcp_conn->tc_rtt= TCP_DEF_RTT;
|
---|
| 216 | tcp_conn->tc_max_mtu= tcp_port->tp_mtu;
|
---|
| 217 | tcp_conn->tc_mtu= tcp_conn->tc_max_mtu;
|
---|
| 218 | tcp_conn->tc_mtutim= 0;
|
---|
| 219 | tcp_conn->tc_error= NW_OK;
|
---|
| 220 | tcp_conn->tc_snd_wnd= TCP_MAX_SND_WND_SIZE;
|
---|
| 221 | tcp_conn->tc_snd_cinc=
|
---|
| 222 | (long)TCP_DEF_MSS*TCP_DEF_MSS/TCP_MAX_SND_WND_SIZE+1;
|
---|
| 223 |
|
---|
| 224 | tcp_conn->tc_rt_time= 0;
|
---|
| 225 | tcp_conn->tc_rt_seq= 0;
|
---|
| 226 | tcp_conn->tc_rt_threshold= tcp_conn->tc_ISS;
|
---|
| 227 |
|
---|
| 228 | for (i=0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++,
|
---|
| 229 | tcp_fd++)
|
---|
| 230 | {
|
---|
| 231 | if (!(tcp_fd->tf_flags & TFF_INUSE))
|
---|
| 232 | continue;
|
---|
| 233 | if (tcp_fd->tf_port != tcp_port)
|
---|
| 234 | continue;
|
---|
| 235 | if (tcp_fd->tf_flags & TFF_IOC_INIT_SP)
|
---|
| 236 | {
|
---|
| 237 | tcp_fd->tf_flags &= ~TFF_IOC_INIT_SP;
|
---|
| 238 | tcp_ioctl(i, tcp_fd->tf_ioreq);
|
---|
| 239 | }
|
---|
| 240 | }
|
---|
| 241 | read_ip_packets(tcp_port);
|
---|
| 242 | return;
|
---|
| 243 |
|
---|
| 244 | default:
|
---|
| 245 | ip_panic(( "unknown state" ));
|
---|
| 246 | break;
|
---|
| 247 | }
|
---|
| 248 | }
|
---|
| 249 |
|
---|
| 250 | PRIVATE int tcp_select(fd, operations)
|
---|
| 251 | int fd;
|
---|
| 252 | unsigned operations;
|
---|
| 253 | {
|
---|
| 254 | int i;
|
---|
| 255 | unsigned resops;
|
---|
| 256 | tcp_fd_t *tcp_fd;
|
---|
| 257 | tcp_conn_t *tcp_conn;
|
---|
| 258 |
|
---|
| 259 | tcp_fd= &tcp_fd_table[fd];
|
---|
| 260 | assert (tcp_fd->tf_flags & TFF_INUSE);
|
---|
| 261 |
|
---|
| 262 | resops= 0;
|
---|
| 263 | if (tcp_fd->tf_flags & TFF_LISTENQ)
|
---|
| 264 | {
|
---|
| 265 | /* Special case for LISTENQ */
|
---|
| 266 | if (operations & SR_SELECT_READ)
|
---|
| 267 | {
|
---|
| 268 | for (i= 0; i<TFL_LISTEN_MAX; i++)
|
---|
| 269 | {
|
---|
| 270 | if (tcp_fd->tf_listenq[i] == NULL)
|
---|
| 271 | continue;
|
---|
| 272 | if (tcp_fd->tf_listenq[i]->tc_connInprogress
|
---|
| 273 | == 0)
|
---|
| 274 | {
|
---|
| 275 | break;
|
---|
| 276 | }
|
---|
| 277 | }
|
---|
| 278 | if (i >= TFL_LISTEN_MAX)
|
---|
| 279 | tcp_fd->tf_flags |= TFF_SEL_READ;
|
---|
| 280 | else
|
---|
| 281 | resops |= SR_SELECT_READ;
|
---|
| 282 | }
|
---|
| 283 | if (operations & SR_SELECT_WRITE)
|
---|
| 284 | {
|
---|
| 285 | /* We can't handles writes. Just return the error
|
---|
| 286 | * when the user tries to write.
|
---|
| 287 | */
|
---|
| 288 | resops |= SR_SELECT_WRITE;
|
---|
| 289 | }
|
---|
| 290 | return resops;
|
---|
| 291 | }
|
---|
| 292 | if (tcp_fd->tf_flags & TFF_CONNECTING)
|
---|
| 293 | {
|
---|
| 294 | /* Special case for CONNECTING */
|
---|
| 295 | if (operations & SR_SELECT_WRITE)
|
---|
| 296 | tcp_fd->tf_flags |= TFF_SEL_WRITE;
|
---|
| 297 | return 0;
|
---|
| 298 | }
|
---|
| 299 | if (operations & SR_SELECT_READ)
|
---|
| 300 | {
|
---|
| 301 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 302 |
|
---|
| 303 | if (!(tcp_fd->tf_flags & TFF_CONNECTED))
|
---|
| 304 | {
|
---|
| 305 | /* We can't handle reads until a connection has been
|
---|
| 306 | * established. Return the error when the user tries
|
---|
| 307 | * to read.
|
---|
| 308 | */
|
---|
| 309 | resops |= SR_SELECT_READ;
|
---|
| 310 | }
|
---|
| 311 | else if (tcp_conn->tc_state == TCS_CLOSED ||
|
---|
| 312 | tcp_sel_read(tcp_conn))
|
---|
| 313 | {
|
---|
| 314 | resops |= SR_SELECT_READ;
|
---|
| 315 | }
|
---|
| 316 | else if (!(operations & SR_SELECT_POLL))
|
---|
| 317 | tcp_fd->tf_flags |= TFF_SEL_READ;
|
---|
| 318 | }
|
---|
| 319 | if (operations & SR_SELECT_WRITE)
|
---|
| 320 | {
|
---|
| 321 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 322 | if (!(tcp_fd->tf_flags & TFF_CONNECTED))
|
---|
| 323 | {
|
---|
| 324 | /* We can't handle writes until a connection has been
|
---|
| 325 | * established. Return the error when the user tries
|
---|
| 326 | * to write.
|
---|
| 327 | */
|
---|
| 328 | resops |= SR_SELECT_WRITE;
|
---|
| 329 | }
|
---|
| 330 | else if (tcp_conn->tc_state == TCS_CLOSED ||
|
---|
| 331 | tcp_conn->tc_flags & TCF_FIN_SENT ||
|
---|
| 332 | tcp_sel_write(tcp_conn))
|
---|
| 333 | {
|
---|
| 334 | resops |= SR_SELECT_WRITE;
|
---|
| 335 | }
|
---|
| 336 | else if (!(operations & SR_SELECT_POLL))
|
---|
| 337 | tcp_fd->tf_flags |= TFF_SEL_WRITE;
|
---|
| 338 | }
|
---|
| 339 | if (operations & SR_SELECT_EXCEPTION)
|
---|
| 340 | {
|
---|
| 341 | /* Should add code for exceptions */
|
---|
| 342 | }
|
---|
| 343 | return resops;
|
---|
| 344 | }
|
---|
| 345 |
|
---|
| 346 | PRIVATE acc_t *tcp_get_data (port, offset, count, for_ioctl)
|
---|
| 347 | int port;
|
---|
| 348 | size_t offset;
|
---|
| 349 | size_t count;
|
---|
| 350 | int for_ioctl;
|
---|
| 351 | {
|
---|
| 352 | tcp_port_t *tcp_port;
|
---|
| 353 | int result;
|
---|
| 354 |
|
---|
| 355 | tcp_port= &tcp_port_table[port];
|
---|
| 356 |
|
---|
| 357 | switch (tcp_port->tp_state)
|
---|
| 358 | {
|
---|
| 359 | case TPS_SETPROTO:
|
---|
| 360 | if (!count)
|
---|
| 361 | {
|
---|
| 362 | result= (int)offset;
|
---|
| 363 | if (result<0)
|
---|
| 364 | {
|
---|
| 365 | tcp_port->tp_state= TPS_ERROR;
|
---|
| 366 | break;
|
---|
| 367 | }
|
---|
| 368 | tcp_port->tp_state= TPS_GETCONF;
|
---|
| 369 | if (tcp_port->tp_flags & TPF_SUSPEND)
|
---|
| 370 | tcp_main(tcp_port);
|
---|
| 371 | return NW_OK;
|
---|
| 372 | }
|
---|
| 373 | assert (!offset);
|
---|
| 374 | assert (count == sizeof(struct nwio_ipopt));
|
---|
| 375 | {
|
---|
| 376 | struct nwio_ipopt *ipopt;
|
---|
| 377 | acc_t *acc;
|
---|
| 378 |
|
---|
| 379 | acc= bf_memreq(sizeof(*ipopt));
|
---|
| 380 | ipopt= (struct nwio_ipopt *)ptr2acc_data(acc);
|
---|
| 381 | ipopt->nwio_flags= NWIO_COPY |
|
---|
| 382 | NWIO_EN_LOC | NWIO_DI_BROAD |
|
---|
| 383 | NWIO_REMANY | NWIO_PROTOSPEC |
|
---|
| 384 | NWIO_HDR_O_ANY | NWIO_RWDATALL;
|
---|
| 385 | ipopt->nwio_proto= IPPROTO_TCP;
|
---|
| 386 | return acc;
|
---|
| 387 | }
|
---|
| 388 | case TPS_MAIN:
|
---|
| 389 | assert(tcp_port->tp_flags & TPF_WRITE_IP);
|
---|
| 390 | if (!count)
|
---|
| 391 | {
|
---|
| 392 | result= (int)offset;
|
---|
| 393 | if (result<0)
|
---|
| 394 | {
|
---|
| 395 | if (result == EDSTNOTRCH)
|
---|
| 396 | {
|
---|
| 397 | if (tcp_port->tp_snd_head)
|
---|
| 398 | {
|
---|
| 399 | tcp_notreach(tcp_port->
|
---|
| 400 | tp_snd_head);
|
---|
| 401 | }
|
---|
| 402 | }
|
---|
| 403 | else
|
---|
| 404 | {
|
---|
| 405 | ip_warning((
|
---|
| 406 | "ip_write failed with error: %d\n",
|
---|
| 407 | result ));
|
---|
| 408 | }
|
---|
| 409 | }
|
---|
| 410 | assert (tcp_port->tp_pack);
|
---|
| 411 | bf_afree (tcp_port->tp_pack);
|
---|
| 412 | tcp_port->tp_pack= 0;
|
---|
| 413 |
|
---|
| 414 | if (tcp_port->tp_flags & TPF_WRITE_SP)
|
---|
| 415 | {
|
---|
| 416 | tcp_port->tp_flags &= ~(TPF_WRITE_SP|
|
---|
| 417 | TPF_WRITE_IP);
|
---|
| 418 | if (tcp_port->tp_snd_head)
|
---|
| 419 | tcp_port_write(tcp_port);
|
---|
| 420 | }
|
---|
| 421 | else
|
---|
| 422 | tcp_port->tp_flags &= ~TPF_WRITE_IP;
|
---|
| 423 | }
|
---|
| 424 | else
|
---|
| 425 | {
|
---|
| 426 | return bf_cut (tcp_port->tp_pack, offset,
|
---|
| 427 | count);
|
---|
| 428 | }
|
---|
| 429 | break;
|
---|
| 430 | default:
|
---|
| 431 | printf("tcp_get_data(%d, 0x%x, 0x%x) called but tp_state= 0x%x\n",
|
---|
| 432 | port, offset, count, tcp_port->tp_state);
|
---|
| 433 | break;
|
---|
| 434 | }
|
---|
| 435 | return NW_OK;
|
---|
| 436 | }
|
---|
| 437 |
|
---|
| 438 | PRIVATE int tcp_put_data (fd, offset, data, for_ioctl)
|
---|
| 439 | int fd;
|
---|
| 440 | size_t offset;
|
---|
| 441 | acc_t *data;
|
---|
| 442 | int for_ioctl;
|
---|
| 443 | {
|
---|
| 444 | tcp_port_t *tcp_port;
|
---|
| 445 | int result;
|
---|
| 446 |
|
---|
| 447 | tcp_port= &tcp_port_table[fd];
|
---|
| 448 |
|
---|
| 449 | switch (tcp_port->tp_state)
|
---|
| 450 | {
|
---|
| 451 | case TPS_GETCONF:
|
---|
| 452 | if (!data)
|
---|
| 453 | {
|
---|
| 454 | result= (int)offset;
|
---|
| 455 | if (result<0)
|
---|
| 456 | {
|
---|
| 457 | tcp_port->tp_state= TPS_ERROR;
|
---|
| 458 | return NW_OK;
|
---|
| 459 | }
|
---|
| 460 | tcp_port->tp_state= TPS_MAIN;
|
---|
| 461 | if (tcp_port->tp_flags & TPF_SUSPEND)
|
---|
| 462 | tcp_main(tcp_port);
|
---|
| 463 | }
|
---|
| 464 | else
|
---|
| 465 | {
|
---|
| 466 | struct nwio_ipconf *ipconf;
|
---|
| 467 |
|
---|
| 468 | data= bf_packIffLess(data, sizeof(*ipconf));
|
---|
| 469 | ipconf= (struct nwio_ipconf *)ptr2acc_data(data);
|
---|
| 470 | assert (ipconf->nwic_flags & NWIC_IPADDR_SET);
|
---|
| 471 | tcp_port->tp_ipaddr= ipconf->nwic_ipaddr;
|
---|
| 472 | tcp_port->tp_subnetmask= ipconf->nwic_netmask;
|
---|
| 473 | tcp_port->tp_mtu= ipconf->nwic_mtu;
|
---|
| 474 | bf_afree(data);
|
---|
| 475 | }
|
---|
| 476 | break;
|
---|
| 477 | case TPS_MAIN:
|
---|
| 478 | assert(tcp_port->tp_flags & TPF_READ_IP);
|
---|
| 479 | if (!data)
|
---|
| 480 | {
|
---|
| 481 | result= (int)offset;
|
---|
| 482 | if (result<0)
|
---|
| 483 | ip_panic(( "ip_read() failed" ));
|
---|
| 484 |
|
---|
| 485 | if (tcp_port->tp_flags & TPF_READ_SP)
|
---|
| 486 | {
|
---|
| 487 | tcp_port->tp_flags &= ~(TPF_READ_SP|
|
---|
| 488 | TPF_READ_IP);
|
---|
| 489 | read_ip_packets(tcp_port);
|
---|
| 490 | }
|
---|
| 491 | else
|
---|
| 492 | tcp_port->tp_flags &= ~TPF_READ_IP;
|
---|
| 493 | }
|
---|
| 494 | else
|
---|
| 495 | {
|
---|
| 496 | assert(!offset);
|
---|
| 497 | /* this is an invalid assertion but ip sends
|
---|
| 498 | * only whole datagrams up */
|
---|
| 499 | tcp_put_pkt(fd, data, bf_bufsize(data));
|
---|
| 500 | }
|
---|
| 501 | break;
|
---|
| 502 | default:
|
---|
| 503 | printf(
|
---|
| 504 | "tcp_put_data(%d, 0x%x, %p) called but tp_state= 0x%x\n",
|
---|
| 505 | fd, offset, data, tcp_port->tp_state);
|
---|
| 506 | break;
|
---|
| 507 | }
|
---|
| 508 | return NW_OK;
|
---|
| 509 | }
|
---|
| 510 |
|
---|
| 511 | /*
|
---|
| 512 | tcp_put_pkt
|
---|
| 513 | */
|
---|
| 514 |
|
---|
| 515 | PRIVATE void tcp_put_pkt(fd, data, datalen)
|
---|
| 516 | int fd;
|
---|
| 517 | acc_t *data;
|
---|
| 518 | size_t datalen;
|
---|
| 519 | {
|
---|
| 520 | tcp_port_t *tcp_port;
|
---|
| 521 | tcp_conn_t *tcp_conn, **conn_p;
|
---|
| 522 | ip_hdr_t *ip_hdr;
|
---|
| 523 | tcp_hdr_t *tcp_hdr;
|
---|
| 524 | acc_t *ip_pack, *tcp_pack;
|
---|
| 525 | size_t ip_datalen, tcp_datalen, ip_hdr_len, tcp_hdr_len;
|
---|
| 526 | u16_t sum, mtu;
|
---|
| 527 | u32_t bits;
|
---|
| 528 | int i, hash;
|
---|
| 529 | ipaddr_t srcaddr, dstaddr, ipaddr, mask;
|
---|
| 530 | tcpport_t srcport, dstport;
|
---|
| 531 |
|
---|
| 532 | tcp_port= &tcp_port_table[fd];
|
---|
| 533 |
|
---|
| 534 | /* Extract the IP header. */
|
---|
| 535 | ip_hdr= (ip_hdr_t *)ptr2acc_data(data);
|
---|
| 536 | ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
|
---|
| 537 | ip_datalen= datalen - ip_hdr_len;
|
---|
| 538 | if (ip_datalen == 0)
|
---|
| 539 | {
|
---|
| 540 | if (ip_hdr->ih_proto == 0)
|
---|
| 541 | {
|
---|
| 542 | /* IP layer reports new IP address */
|
---|
| 543 | ipaddr= ip_hdr->ih_src;
|
---|
| 544 | mask= ip_hdr->ih_dst;
|
---|
| 545 | mtu= ntohs(ip_hdr->ih_length);
|
---|
| 546 | tcp_port->tp_ipaddr= ipaddr;
|
---|
| 547 | tcp_port->tp_subnetmask= mask;
|
---|
| 548 | tcp_port->tp_mtu= mtu;
|
---|
| 549 | DBLOCK(1, printf("tcp_put_pkt: using address ");
|
---|
| 550 | writeIpAddr(ipaddr);
|
---|
| 551 | printf(", netmask ");
|
---|
| 552 | writeIpAddr(mask);
|
---|
| 553 | printf(", mtu %u\n", mtu));
|
---|
| 554 | for (i= 0, tcp_conn= tcp_conn_table+i;
|
---|
| 555 | i<TCP_CONN_NR; i++, tcp_conn++)
|
---|
| 556 | {
|
---|
| 557 | if (!(tcp_conn->tc_flags & TCF_INUSE))
|
---|
| 558 | continue;
|
---|
| 559 | if (tcp_conn->tc_port != tcp_port)
|
---|
| 560 | continue;
|
---|
| 561 | tcp_conn->tc_locaddr= ipaddr;
|
---|
| 562 | }
|
---|
| 563 | }
|
---|
| 564 | else
|
---|
| 565 | DBLOCK(1, printf("tcp_put_pkt: no TCP header\n"));
|
---|
| 566 | bf_afree(data);
|
---|
| 567 | return;
|
---|
| 568 | }
|
---|
| 569 | data->acc_linkC++;
|
---|
| 570 | ip_pack= data;
|
---|
| 571 | ip_pack= bf_align(ip_pack, ip_hdr_len, 4);
|
---|
| 572 | ip_hdr= (ip_hdr_t *)ptr2acc_data(ip_pack);
|
---|
| 573 | data= bf_delhead(data, ip_hdr_len);
|
---|
| 574 |
|
---|
| 575 | /* Compute the checksum */
|
---|
| 576 | sum= tcp_pack_oneCsum(ip_hdr, data);
|
---|
| 577 |
|
---|
| 578 | /* Extract the TCP header */
|
---|
| 579 | if (ip_datalen < TCP_MIN_HDR_SIZE)
|
---|
| 580 | {
|
---|
| 581 | DBLOCK(1, printf("truncated TCP header\n"));
|
---|
| 582 | bf_afree(ip_pack);
|
---|
| 583 | bf_afree(data);
|
---|
| 584 | return;
|
---|
| 585 | }
|
---|
| 586 | data= bf_packIffLess(data, TCP_MIN_HDR_SIZE);
|
---|
| 587 | tcp_hdr= (tcp_hdr_t *)ptr2acc_data(data);
|
---|
| 588 | tcp_hdr_len= (tcp_hdr->th_data_off & TH_DO_MASK) >> 2;
|
---|
| 589 | /* actualy (>> 4) << 2 */
|
---|
| 590 | if (ip_datalen < tcp_hdr_len || tcp_hdr_len < TCP_MIN_HDR_SIZE)
|
---|
| 591 | {
|
---|
| 592 | if (tcp_hdr_len < TCP_MIN_HDR_SIZE)
|
---|
| 593 | {
|
---|
| 594 | DBLOCK(1, printf("strange tcp header length %d\n",
|
---|
| 595 | tcp_hdr_len));
|
---|
| 596 | }
|
---|
| 597 | else
|
---|
| 598 | {
|
---|
| 599 | DBLOCK(1, printf("truncated TCP header\n"));
|
---|
| 600 | }
|
---|
| 601 | bf_afree(ip_pack);
|
---|
| 602 | bf_afree(data);
|
---|
| 603 | return;
|
---|
| 604 | }
|
---|
| 605 | data->acc_linkC++;
|
---|
| 606 | tcp_pack= data;
|
---|
| 607 | tcp_pack= bf_align(tcp_pack, tcp_hdr_len, 4);
|
---|
| 608 | tcp_hdr= (tcp_hdr_t *)ptr2acc_data(tcp_pack);
|
---|
| 609 | if (ip_datalen == tcp_hdr_len)
|
---|
| 610 | {
|
---|
| 611 | bf_afree(data);
|
---|
| 612 | data= NULL;
|
---|
| 613 | }
|
---|
| 614 | else
|
---|
| 615 | data= bf_delhead(data, tcp_hdr_len);
|
---|
| 616 | tcp_datalen= ip_datalen-tcp_hdr_len;
|
---|
| 617 |
|
---|
| 618 | if ((u16_t)~sum)
|
---|
| 619 | {
|
---|
| 620 | DBLOCK(1, printf("checksum error in tcp packet\n");
|
---|
| 621 | printf("tcp_pack_oneCsum(...)= 0x%x length= %d\n",
|
---|
| 622 | (u16_t)~sum, tcp_datalen);
|
---|
| 623 | printf("src ip_addr= "); writeIpAddr(ip_hdr->ih_src);
|
---|
| 624 | printf("\n"));
|
---|
| 625 | bf_afree(ip_pack);
|
---|
| 626 | bf_afree(tcp_pack);
|
---|
| 627 | bf_afree(data);
|
---|
| 628 | return;
|
---|
| 629 | }
|
---|
| 630 |
|
---|
| 631 | srcaddr= ip_hdr->ih_src;
|
---|
| 632 | dstaddr= ip_hdr->ih_dst;
|
---|
| 633 | srcport= tcp_hdr->th_srcport;
|
---|
| 634 | dstport= tcp_hdr->th_dstport;
|
---|
| 635 | bits= srcaddr ^ dstaddr ^ srcport ^ dstport;
|
---|
| 636 | bits= (bits >> 16) ^ bits;
|
---|
| 637 | bits= (bits >> 8) ^ bits;
|
---|
| 638 | hash= ((bits >> TCP_CONN_HASH_SHIFT) ^ bits) & (TCP_CONN_HASH_NR-1);
|
---|
| 639 | conn_p= tcp_port->tp_conn_hash[hash];
|
---|
| 640 | if (conn_p[0]->tc_locport == dstport &&
|
---|
| 641 | conn_p[0]->tc_remport == srcport &&
|
---|
| 642 | conn_p[0]->tc_remaddr == srcaddr &&
|
---|
| 643 | conn_p[0]->tc_locaddr == dstaddr)
|
---|
| 644 | {
|
---|
| 645 | tcp_conn= conn_p[0];
|
---|
| 646 | }
|
---|
| 647 | else if (conn_p[1]->tc_locport == dstport &&
|
---|
| 648 | conn_p[1]->tc_remport == srcport &&
|
---|
| 649 | conn_p[1]->tc_remaddr == srcaddr &&
|
---|
| 650 | conn_p[1]->tc_locaddr == dstaddr)
|
---|
| 651 | {
|
---|
| 652 | tcp_conn= conn_p[1];
|
---|
| 653 | conn_p[1]= conn_p[0];
|
---|
| 654 | conn_p[0]= tcp_conn;
|
---|
| 655 | }
|
---|
| 656 | else if (conn_p[2]->tc_locport == dstport &&
|
---|
| 657 | conn_p[2]->tc_remport == srcport &&
|
---|
| 658 | conn_p[2]->tc_remaddr == srcaddr &&
|
---|
| 659 | conn_p[2]->tc_locaddr == dstaddr)
|
---|
| 660 | {
|
---|
| 661 | tcp_conn= conn_p[2];
|
---|
| 662 | conn_p[2]= conn_p[1];
|
---|
| 663 | conn_p[1]= conn_p[0];
|
---|
| 664 | conn_p[0]= tcp_conn;
|
---|
| 665 | }
|
---|
| 666 | else if (conn_p[3]->tc_locport == dstport &&
|
---|
| 667 | conn_p[3]->tc_remport == srcport &&
|
---|
| 668 | conn_p[3]->tc_remaddr == srcaddr &&
|
---|
| 669 | conn_p[3]->tc_locaddr == dstaddr)
|
---|
| 670 | {
|
---|
| 671 | tcp_conn= conn_p[3];
|
---|
| 672 | conn_p[3]= conn_p[2];
|
---|
| 673 | conn_p[2]= conn_p[1];
|
---|
| 674 | conn_p[1]= conn_p[0];
|
---|
| 675 | conn_p[0]= tcp_conn;
|
---|
| 676 | }
|
---|
| 677 | else
|
---|
| 678 | tcp_conn= NULL;
|
---|
| 679 | if ((tcp_conn != NULL && tcp_conn->tc_state == TCS_CLOSED) ||
|
---|
| 680 | (tcp_hdr->th_flags & THF_SYN))
|
---|
| 681 | {
|
---|
| 682 | tcp_conn= NULL;
|
---|
| 683 | }
|
---|
| 684 |
|
---|
| 685 | if (tcp_conn == NULL)
|
---|
| 686 | {
|
---|
| 687 | tcp_conn= find_best_conn(ip_hdr, tcp_hdr);
|
---|
| 688 | if (!tcp_conn)
|
---|
| 689 | {
|
---|
| 690 | /* listen backlog hack */
|
---|
| 691 | bf_afree(ip_pack);
|
---|
| 692 | bf_afree(tcp_pack);
|
---|
| 693 | bf_afree(data);
|
---|
| 694 | return;
|
---|
| 695 | }
|
---|
| 696 | if (tcp_conn->tc_state != TCS_CLOSED)
|
---|
| 697 | {
|
---|
| 698 | conn_p[3]= conn_p[2];
|
---|
| 699 | conn_p[2]= conn_p[1];
|
---|
| 700 | conn_p[1]= conn_p[0];
|
---|
| 701 | conn_p[0]= tcp_conn;
|
---|
| 702 | }
|
---|
| 703 | }
|
---|
| 704 | assert(tcp_conn->tc_busy == 0);
|
---|
| 705 | tcp_conn->tc_busy++;
|
---|
| 706 | tcp_frag2conn(tcp_conn, ip_hdr, tcp_hdr, data, tcp_datalen);
|
---|
| 707 | tcp_conn->tc_busy--;
|
---|
| 708 | bf_afree(ip_pack);
|
---|
| 709 | bf_afree(tcp_pack);
|
---|
| 710 | }
|
---|
| 711 |
|
---|
| 712 |
|
---|
| 713 | PUBLIC int tcp_open (port, srfd, get_userdata, put_userdata, put_pkt,
|
---|
| 714 | select_res)
|
---|
| 715 | int port;
|
---|
| 716 | int srfd;
|
---|
| 717 | get_userdata_t get_userdata;
|
---|
| 718 | put_userdata_t put_userdata;
|
---|
| 719 | put_pkt_t put_pkt;
|
---|
| 720 | select_res_t select_res;
|
---|
| 721 | {
|
---|
| 722 | int i, j;
|
---|
| 723 |
|
---|
| 724 | tcp_fd_t *tcp_fd;
|
---|
| 725 |
|
---|
| 726 | for (i=0; i<TCP_FD_NR && (tcp_fd_table[i].tf_flags & TFF_INUSE);
|
---|
| 727 | i++);
|
---|
| 728 | if (i>=TCP_FD_NR)
|
---|
| 729 | {
|
---|
| 730 | return EAGAIN;
|
---|
| 731 | }
|
---|
| 732 |
|
---|
| 733 | tcp_fd= &tcp_fd_table[i];
|
---|
| 734 |
|
---|
| 735 | tcp_fd->tf_flags= TFF_INUSE;
|
---|
| 736 | tcp_fd->tf_flags |= TFF_PUSH_DATA;
|
---|
| 737 |
|
---|
| 738 | tcp_fd->tf_port= &tcp_port_table[port];
|
---|
| 739 | tcp_fd->tf_srfd= srfd;
|
---|
| 740 | tcp_fd->tf_tcpconf.nwtc_flags= TCP_DEF_CONF;
|
---|
| 741 | tcp_fd->tf_tcpconf.nwtc_remaddr= 0;
|
---|
| 742 | tcp_fd->tf_tcpconf.nwtc_remport= 0;
|
---|
| 743 | tcp_fd->tf_tcpopt.nwto_flags= TCP_DEF_OPT;
|
---|
| 744 | tcp_fd->tf_get_userdata= get_userdata;
|
---|
| 745 | tcp_fd->tf_put_userdata= put_userdata;
|
---|
| 746 | tcp_fd->tf_select_res= select_res;
|
---|
| 747 | tcp_fd->tf_conn= 0;
|
---|
| 748 | tcp_fd->tf_error= 0;
|
---|
| 749 | for (j= 0; j<TFL_LISTEN_MAX; j++)
|
---|
| 750 | tcp_fd->tf_listenq[j]= NULL;
|
---|
| 751 | return i;
|
---|
| 752 | }
|
---|
| 753 |
|
---|
| 754 | /*
|
---|
| 755 | tcp_ioctl
|
---|
| 756 | */
|
---|
| 757 | PUBLIC int tcp_ioctl (fd, req)
|
---|
| 758 | int fd;
|
---|
| 759 | ioreq_t req;
|
---|
| 760 | {
|
---|
| 761 | tcp_fd_t *tcp_fd;
|
---|
| 762 | tcp_port_t *tcp_port;
|
---|
| 763 | tcp_conn_t *tcp_conn;
|
---|
| 764 | nwio_tcpconf_t *tcp_conf;
|
---|
| 765 | nwio_tcpopt_t *tcp_opt;
|
---|
| 766 | tcp_cookie_t *cookiep;
|
---|
| 767 | acc_t *acc, *conf_acc, *opt_acc;
|
---|
| 768 | int result, *bytesp;
|
---|
| 769 | u8_t rndbits[RAND256_BUFSIZE];
|
---|
| 770 |
|
---|
| 771 | tcp_fd= &tcp_fd_table[fd];
|
---|
| 772 |
|
---|
| 773 | assert (tcp_fd->tf_flags & TFF_INUSE);
|
---|
| 774 |
|
---|
| 775 | tcp_port= tcp_fd->tf_port;
|
---|
| 776 | tcp_fd->tf_flags |= TFF_IOCTL_IP;
|
---|
| 777 | tcp_fd->tf_ioreq= req;
|
---|
| 778 |
|
---|
| 779 | if (tcp_port->tp_state != TPS_MAIN)
|
---|
| 780 | {
|
---|
| 781 | tcp_fd->tf_flags |= TFF_IOC_INIT_SP;
|
---|
| 782 | return NW_SUSPEND;
|
---|
| 783 | }
|
---|
| 784 |
|
---|
| 785 | switch (req)
|
---|
| 786 | {
|
---|
| 787 | case NWIOSTCPCONF:
|
---|
| 788 | if ((tcp_fd->tf_flags & TFF_CONNECTED) ||
|
---|
| 789 | (tcp_fd->tf_flags & TFF_CONNECTING) ||
|
---|
| 790 | (tcp_fd->tf_flags & TFF_LISTENQ))
|
---|
| 791 | {
|
---|
| 792 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 793 | reply_thr_get (tcp_fd, EISCONN, TRUE);
|
---|
| 794 | result= NW_OK;
|
---|
| 795 | break;
|
---|
| 796 | }
|
---|
| 797 | result= tcp_setconf(tcp_fd);
|
---|
| 798 | break;
|
---|
| 799 | case NWIOGTCPCONF:
|
---|
| 800 | conf_acc= bf_memreq(sizeof(*tcp_conf));
|
---|
| 801 | assert (conf_acc->acc_length == sizeof(*tcp_conf));
|
---|
| 802 | tcp_conf= (nwio_tcpconf_t *)ptr2acc_data(conf_acc);
|
---|
| 803 |
|
---|
| 804 | *tcp_conf= tcp_fd->tf_tcpconf;
|
---|
| 805 | if (tcp_fd->tf_flags & TFF_CONNECTED)
|
---|
| 806 | {
|
---|
| 807 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 808 | tcp_conf->nwtc_locport= tcp_conn->tc_locport;
|
---|
| 809 | tcp_conf->nwtc_remaddr= tcp_conn->tc_remaddr;
|
---|
| 810 | tcp_conf->nwtc_remport= tcp_conn->tc_remport;
|
---|
| 811 | }
|
---|
| 812 | tcp_conf->nwtc_locaddr= tcp_fd->tf_port->tp_ipaddr;
|
---|
| 813 | result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
|
---|
| 814 | 0, conf_acc, TRUE);
|
---|
| 815 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 816 | reply_thr_put(tcp_fd, result, TRUE);
|
---|
| 817 | result= NW_OK;
|
---|
| 818 | break;
|
---|
| 819 | case NWIOSTCPOPT:
|
---|
| 820 | result= tcp_setopt(tcp_fd);
|
---|
| 821 | break;
|
---|
| 822 | case NWIOGTCPOPT:
|
---|
| 823 | opt_acc= bf_memreq(sizeof(*tcp_opt));
|
---|
| 824 | assert (opt_acc->acc_length == sizeof(*tcp_opt));
|
---|
| 825 | tcp_opt= (nwio_tcpopt_t *)ptr2acc_data(opt_acc);
|
---|
| 826 |
|
---|
| 827 | *tcp_opt= tcp_fd->tf_tcpopt;
|
---|
| 828 | result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
|
---|
| 829 | 0, opt_acc, TRUE);
|
---|
| 830 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 831 | reply_thr_put(tcp_fd, result, TRUE);
|
---|
| 832 | result= NW_OK;
|
---|
| 833 | break;
|
---|
| 834 | case NWIOTCPCONN:
|
---|
| 835 | if (tcp_fd->tf_flags & TFF_CONNECTING)
|
---|
| 836 | {
|
---|
| 837 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 838 | reply_thr_get (tcp_fd, EALREADY, TRUE);
|
---|
| 839 | result= NW_OK;
|
---|
| 840 | break;
|
---|
| 841 | }
|
---|
| 842 | if (tcp_fd->tf_flags & TFF_CONNECTED)
|
---|
| 843 | {
|
---|
| 844 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 845 | reply_thr_get (tcp_fd, EISCONN, TRUE);
|
---|
| 846 | result= NW_OK;
|
---|
| 847 | break;
|
---|
| 848 | }
|
---|
| 849 | result= tcp_connect(tcp_fd);
|
---|
| 850 | if (result == NW_OK)
|
---|
| 851 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 852 | break;
|
---|
| 853 | case NWIOTCPLISTEN:
|
---|
| 854 | case NWIOTCPLISTENQ:
|
---|
| 855 | if ((tcp_fd->tf_flags & TFF_CONNECTED) ||
|
---|
| 856 | (tcp_fd->tf_flags & TFF_LISTENQ) ||
|
---|
| 857 | (tcp_fd->tf_flags & TFF_CONNECTING))
|
---|
| 858 | {
|
---|
| 859 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 860 | reply_thr_get (tcp_fd, EISCONN, TRUE);
|
---|
| 861 | result= NW_OK;
|
---|
| 862 | break;
|
---|
| 863 | }
|
---|
| 864 | result= tcp_listen(tcp_fd, (req == NWIOTCPLISTENQ));
|
---|
| 865 | break;
|
---|
| 866 | case NWIOTCPSHUTDOWN:
|
---|
| 867 | if (!(tcp_fd->tf_flags & TFF_CONNECTED))
|
---|
| 868 | {
|
---|
| 869 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 870 | reply_thr_get (tcp_fd, ENOTCONN, TRUE);
|
---|
| 871 | result= NW_OK;
|
---|
| 872 | break;
|
---|
| 873 | }
|
---|
| 874 | tcp_fd->tf_flags |= TFF_IOCTL_IP;
|
---|
| 875 | tcp_fd->tf_ioreq= req;
|
---|
| 876 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 877 |
|
---|
| 878 | tcp_conn->tc_busy++;
|
---|
| 879 | tcp_fd_write(tcp_conn);
|
---|
| 880 | tcp_conn->tc_busy--;
|
---|
| 881 | tcp_conn_write(tcp_conn, 0);
|
---|
| 882 | if (!(tcp_fd->tf_flags & TFF_IOCTL_IP))
|
---|
| 883 | result= NW_OK;
|
---|
| 884 | else
|
---|
| 885 | result= NW_SUSPEND;
|
---|
| 886 | break;
|
---|
| 887 | case NWIOTCPPUSH:
|
---|
| 888 | if (!(tcp_fd->tf_flags & TFF_CONNECTED))
|
---|
| 889 | {
|
---|
| 890 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 891 | reply_thr_get (tcp_fd, ENOTCONN, TRUE);
|
---|
| 892 | result= NW_OK;
|
---|
| 893 | break;
|
---|
| 894 | }
|
---|
| 895 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 896 | tcp_conn->tc_SND_PSH= tcp_conn->tc_SND_NXT;
|
---|
| 897 | tcp_conn->tc_flags &= ~TCF_NO_PUSH;
|
---|
| 898 | tcp_conn->tc_flags |= TCF_PUSH_NOW;
|
---|
| 899 |
|
---|
| 900 | /* Start the timer (if necessary) */
|
---|
| 901 | if (tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_UNA)
|
---|
| 902 | tcp_set_send_timer(tcp_conn);
|
---|
| 903 |
|
---|
| 904 | tcp_conn_write(tcp_conn, 0);
|
---|
| 905 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 906 | reply_thr_get (tcp_fd, NW_OK, TRUE);
|
---|
| 907 | result= NW_OK;
|
---|
| 908 | break;
|
---|
| 909 | case NWIOGTCPCOOKIE:
|
---|
| 910 | if (!(tcp_fd->tf_flags & TFF_COOKIE))
|
---|
| 911 | {
|
---|
| 912 | tcp_fd->tf_cookie.tc_ref= fd;
|
---|
| 913 | rand256(rndbits);
|
---|
| 914 | assert(sizeof(tcp_fd->tf_cookie.tc_secret) <=
|
---|
| 915 | RAND256_BUFSIZE);
|
---|
| 916 | memcpy(tcp_fd->tf_cookie.tc_secret,
|
---|
| 917 | rndbits, sizeof(tcp_fd->tf_cookie.tc_secret));
|
---|
| 918 | tcp_fd->tf_flags |= TFF_COOKIE;
|
---|
| 919 | }
|
---|
| 920 | acc= bf_memreq(sizeof(*cookiep));
|
---|
| 921 | cookiep= (tcp_cookie_t *)ptr2acc_data(acc);
|
---|
| 922 |
|
---|
| 923 | *cookiep= tcp_fd->tf_cookie;
|
---|
| 924 | result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
|
---|
| 925 | 0, acc, TRUE);
|
---|
| 926 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 927 | reply_thr_put(tcp_fd, result, TRUE);
|
---|
| 928 | result= NW_OK;
|
---|
| 929 | break;
|
---|
| 930 | case NWIOTCPACCEPTTO:
|
---|
| 931 | result= tcp_acceptto(tcp_fd);
|
---|
| 932 | break;
|
---|
| 933 | case FIONREAD:
|
---|
| 934 | acc= bf_memreq(sizeof(*bytesp));
|
---|
| 935 | bytesp= (int *)ptr2acc_data(acc);
|
---|
| 936 | tcp_bytesavailable(tcp_fd, bytesp);
|
---|
| 937 | result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
|
---|
| 938 | 0, acc, TRUE);
|
---|
| 939 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 940 | reply_thr_put(tcp_fd, result, TRUE);
|
---|
| 941 | result= NW_OK;
|
---|
| 942 | break;
|
---|
| 943 |
|
---|
| 944 | case NWIOTCPGERROR:
|
---|
| 945 | acc= bf_memreq(sizeof(*bytesp));
|
---|
| 946 | bytesp= (int *)ptr2acc_data(acc);
|
---|
| 947 | *bytesp= -tcp_fd->tf_error; /* Errors are positive in
|
---|
| 948 | * user space.
|
---|
| 949 | */
|
---|
| 950 | tcp_fd->tf_error= 0;
|
---|
| 951 | result= (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd,
|
---|
| 952 | 0, acc, TRUE);
|
---|
| 953 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 954 | reply_thr_put(tcp_fd, result, TRUE);
|
---|
| 955 | result= NW_OK;
|
---|
| 956 | break;
|
---|
| 957 |
|
---|
| 958 | default:
|
---|
| 959 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 960 | reply_thr_get(tcp_fd, EBADIOCTL, TRUE);
|
---|
| 961 | result= NW_OK;
|
---|
| 962 | break;
|
---|
| 963 | }
|
---|
| 964 | return result;
|
---|
| 965 | }
|
---|
| 966 |
|
---|
| 967 |
|
---|
| 968 | /*
|
---|
| 969 | tcp_setconf
|
---|
| 970 | */
|
---|
| 971 |
|
---|
| 972 | PRIVATE int tcp_setconf(tcp_fd)
|
---|
| 973 | tcp_fd_t *tcp_fd;
|
---|
| 974 | {
|
---|
| 975 | nwio_tcpconf_t *tcpconf;
|
---|
| 976 | nwio_tcpconf_t oldconf, newconf;
|
---|
| 977 | acc_t *data;
|
---|
| 978 | tcp_fd_t *fd_ptr;
|
---|
| 979 | unsigned int new_en_flags, new_di_flags,
|
---|
| 980 | old_en_flags, old_di_flags, all_flags, flags;
|
---|
| 981 | int i;
|
---|
| 982 |
|
---|
| 983 | data= (*tcp_fd->tf_get_userdata)
|
---|
| 984 | (tcp_fd->tf_srfd, 0,
|
---|
| 985 | sizeof(nwio_tcpconf_t), TRUE);
|
---|
| 986 |
|
---|
| 987 | if (!data)
|
---|
| 988 | return EFAULT;
|
---|
| 989 |
|
---|
| 990 | data= bf_packIffLess(data, sizeof(nwio_tcpconf_t));
|
---|
| 991 | assert (data->acc_length == sizeof(nwio_tcpconf_t));
|
---|
| 992 |
|
---|
| 993 | tcpconf= (nwio_tcpconf_t *)ptr2acc_data(data);
|
---|
| 994 | oldconf= tcp_fd->tf_tcpconf;
|
---|
| 995 | newconf= *tcpconf;
|
---|
| 996 |
|
---|
| 997 | old_en_flags= oldconf.nwtc_flags & 0xffff;
|
---|
| 998 | old_di_flags= (oldconf.nwtc_flags >> 16) &
|
---|
| 999 | 0xffff;
|
---|
| 1000 | new_en_flags= newconf.nwtc_flags & 0xffff;
|
---|
| 1001 | new_di_flags= (newconf.nwtc_flags >> 16) &
|
---|
| 1002 | 0xffff;
|
---|
| 1003 | if (new_en_flags & new_di_flags)
|
---|
| 1004 | {
|
---|
| 1005 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1006 | reply_thr_get(tcp_fd, EBADMODE, TRUE);
|
---|
| 1007 | bf_afree(data);
|
---|
| 1008 | return NW_OK;
|
---|
| 1009 | }
|
---|
| 1010 |
|
---|
| 1011 | /* NWTC_ACC_MASK */
|
---|
| 1012 | if (new_di_flags & NWTC_ACC_MASK)
|
---|
| 1013 | {
|
---|
| 1014 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1015 | reply_thr_get(tcp_fd, EBADMODE, TRUE);
|
---|
| 1016 | bf_afree(data);
|
---|
| 1017 | return NW_OK;
|
---|
| 1018 | /* access modes can't be disabled */
|
---|
| 1019 | }
|
---|
| 1020 |
|
---|
| 1021 | if (!(new_en_flags & NWTC_ACC_MASK))
|
---|
| 1022 | new_en_flags |= (old_en_flags & NWTC_ACC_MASK);
|
---|
| 1023 |
|
---|
| 1024 | /* NWTC_LOCPORT_MASK */
|
---|
| 1025 | if (new_di_flags & NWTC_LOCPORT_MASK)
|
---|
| 1026 | {
|
---|
| 1027 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1028 | reply_thr_get(tcp_fd, EBADMODE, TRUE);
|
---|
| 1029 | bf_afree(data);
|
---|
| 1030 | return NW_OK;
|
---|
| 1031 | /* the loc ports can't be disabled */
|
---|
| 1032 | }
|
---|
| 1033 | if (!(new_en_flags & NWTC_LOCPORT_MASK))
|
---|
| 1034 | {
|
---|
| 1035 | new_en_flags |= (old_en_flags &
|
---|
| 1036 | NWTC_LOCPORT_MASK);
|
---|
| 1037 | newconf.nwtc_locport= oldconf.nwtc_locport;
|
---|
| 1038 | }
|
---|
| 1039 | else if ((new_en_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL)
|
---|
| 1040 | {
|
---|
| 1041 | newconf.nwtc_locport= find_unused_port(tcp_fd-
|
---|
| 1042 | tcp_fd_table);
|
---|
| 1043 | }
|
---|
| 1044 | else if ((new_en_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET)
|
---|
| 1045 | {
|
---|
| 1046 | if (!newconf.nwtc_locport)
|
---|
| 1047 | {
|
---|
| 1048 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1049 | reply_thr_get(tcp_fd, EBADMODE, TRUE);
|
---|
| 1050 | bf_afree(data);
|
---|
| 1051 | return NW_OK;
|
---|
| 1052 | }
|
---|
| 1053 | }
|
---|
| 1054 |
|
---|
| 1055 | /* NWTC_REMADDR_MASK */
|
---|
| 1056 | if (!((new_en_flags | new_di_flags) &
|
---|
| 1057 | NWTC_REMADDR_MASK))
|
---|
| 1058 | {
|
---|
| 1059 | new_en_flags |= (old_en_flags &
|
---|
| 1060 | NWTC_REMADDR_MASK);
|
---|
| 1061 | new_di_flags |= (old_di_flags &
|
---|
| 1062 | NWTC_REMADDR_MASK);
|
---|
| 1063 | newconf.nwtc_remaddr= oldconf.nwtc_remaddr;
|
---|
| 1064 | }
|
---|
| 1065 | else if (new_en_flags & NWTC_SET_RA)
|
---|
| 1066 | {
|
---|
| 1067 | if (!newconf.nwtc_remaddr)
|
---|
| 1068 | {
|
---|
| 1069 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1070 | reply_thr_get(tcp_fd, EBADMODE, TRUE);
|
---|
| 1071 | bf_afree(data);
|
---|
| 1072 | return NW_OK;
|
---|
| 1073 | }
|
---|
| 1074 | }
|
---|
| 1075 | else
|
---|
| 1076 | {
|
---|
| 1077 | assert (new_di_flags & NWTC_REMADDR_MASK);
|
---|
| 1078 | newconf.nwtc_remaddr= 0;
|
---|
| 1079 | }
|
---|
| 1080 |
|
---|
| 1081 | /* NWTC_REMPORT_MASK */
|
---|
| 1082 | if (!((new_en_flags | new_di_flags) & NWTC_REMPORT_MASK))
|
---|
| 1083 | {
|
---|
| 1084 | new_en_flags |= (old_en_flags &
|
---|
| 1085 | NWTC_REMPORT_MASK);
|
---|
| 1086 | new_di_flags |= (old_di_flags &
|
---|
| 1087 | NWTC_REMPORT_MASK);
|
---|
| 1088 | newconf.nwtc_remport=
|
---|
| 1089 | oldconf.nwtc_remport;
|
---|
| 1090 | }
|
---|
| 1091 | else if (new_en_flags & NWTC_SET_RP)
|
---|
| 1092 | {
|
---|
| 1093 | if (!newconf.nwtc_remport)
|
---|
| 1094 | {
|
---|
| 1095 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1096 | reply_thr_get(tcp_fd, EBADMODE, TRUE);
|
---|
| 1097 | bf_afree(data);
|
---|
| 1098 | return NW_OK;
|
---|
| 1099 | }
|
---|
| 1100 | }
|
---|
| 1101 | else
|
---|
| 1102 | {
|
---|
| 1103 | assert (new_di_flags & NWTC_REMPORT_MASK);
|
---|
| 1104 | newconf.nwtc_remport= 0;
|
---|
| 1105 | }
|
---|
| 1106 |
|
---|
| 1107 | newconf.nwtc_flags= ((unsigned long)new_di_flags
|
---|
| 1108 | << 16) | new_en_flags;
|
---|
| 1109 | all_flags= new_en_flags | new_di_flags;
|
---|
| 1110 |
|
---|
| 1111 | /* check the access modes */
|
---|
| 1112 | if ((all_flags & NWTC_LOCPORT_MASK) != NWTC_LP_UNSET)
|
---|
| 1113 | {
|
---|
| 1114 | for (i=0, fd_ptr= tcp_fd_table; i<TCP_FD_NR; i++, fd_ptr++)
|
---|
| 1115 | {
|
---|
| 1116 | if (fd_ptr == tcp_fd)
|
---|
| 1117 | continue;
|
---|
| 1118 | if (!(fd_ptr->tf_flags & TFF_INUSE))
|
---|
| 1119 | continue;
|
---|
| 1120 | if (fd_ptr->tf_port != tcp_fd->tf_port)
|
---|
| 1121 | continue;
|
---|
| 1122 | flags= fd_ptr->tf_tcpconf.nwtc_flags;
|
---|
| 1123 | if ((flags & NWTC_LOCPORT_MASK) == NWTC_LP_UNSET)
|
---|
| 1124 | continue;
|
---|
| 1125 | if (fd_ptr->tf_tcpconf.nwtc_locport !=
|
---|
| 1126 | newconf.nwtc_locport)
|
---|
| 1127 | continue;
|
---|
| 1128 | if ((flags & NWTC_ACC_MASK) != (all_flags &
|
---|
| 1129 | NWTC_ACC_MASK) ||
|
---|
| 1130 | (all_flags & NWTC_ACC_MASK) == NWTC_EXCL)
|
---|
| 1131 | {
|
---|
| 1132 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1133 | reply_thr_get(tcp_fd, EADDRINUSE, TRUE);
|
---|
| 1134 | bf_afree(data);
|
---|
| 1135 | return NW_OK;
|
---|
| 1136 | }
|
---|
| 1137 | }
|
---|
| 1138 | }
|
---|
| 1139 |
|
---|
| 1140 | tcp_fd->tf_tcpconf= newconf;
|
---|
| 1141 |
|
---|
| 1142 | if ((all_flags & NWTC_ACC_MASK) &&
|
---|
| 1143 | ((all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET ||
|
---|
| 1144 | (all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL) &&
|
---|
| 1145 | (all_flags & NWTC_REMADDR_MASK) &&
|
---|
| 1146 | (all_flags & NWTC_REMPORT_MASK))
|
---|
| 1147 | tcp_fd->tf_flags |= TFF_CONF_SET;
|
---|
| 1148 | else
|
---|
| 1149 | {
|
---|
| 1150 | tcp_fd->tf_flags &= ~TFF_CONF_SET;
|
---|
| 1151 | }
|
---|
| 1152 | bf_afree(data);
|
---|
| 1153 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1154 | reply_thr_get(tcp_fd, NW_OK, TRUE);
|
---|
| 1155 | return NW_OK;
|
---|
| 1156 | }
|
---|
| 1157 |
|
---|
| 1158 |
|
---|
| 1159 | /*
|
---|
| 1160 | tcp_setopt
|
---|
| 1161 | */
|
---|
| 1162 |
|
---|
| 1163 | PRIVATE int tcp_setopt(tcp_fd)
|
---|
| 1164 | tcp_fd_t *tcp_fd;
|
---|
| 1165 | {
|
---|
| 1166 | nwio_tcpopt_t *tcpopt;
|
---|
| 1167 | nwio_tcpopt_t oldopt, newopt;
|
---|
| 1168 | acc_t *data;
|
---|
| 1169 | unsigned int new_en_flags, new_di_flags,
|
---|
| 1170 | old_en_flags, old_di_flags;
|
---|
| 1171 |
|
---|
| 1172 | data= (*tcp_fd->tf_get_userdata) (tcp_fd->tf_srfd, 0,
|
---|
| 1173 | sizeof(nwio_tcpopt_t), TRUE);
|
---|
| 1174 |
|
---|
| 1175 | if (!data)
|
---|
| 1176 | return EFAULT;
|
---|
| 1177 |
|
---|
| 1178 | data= bf_packIffLess(data, sizeof(nwio_tcpopt_t));
|
---|
| 1179 | assert (data->acc_length == sizeof(nwio_tcpopt_t));
|
---|
| 1180 |
|
---|
| 1181 | tcpopt= (nwio_tcpopt_t *)ptr2acc_data(data);
|
---|
| 1182 | oldopt= tcp_fd->tf_tcpopt;
|
---|
| 1183 | newopt= *tcpopt;
|
---|
| 1184 |
|
---|
| 1185 | old_en_flags= oldopt.nwto_flags & 0xffff;
|
---|
| 1186 | old_di_flags= (oldopt.nwto_flags >> 16) & 0xffff;
|
---|
| 1187 | new_en_flags= newopt.nwto_flags & 0xffff;
|
---|
| 1188 | new_di_flags= (newopt.nwto_flags >> 16) & 0xffff;
|
---|
| 1189 | if (new_en_flags & new_di_flags)
|
---|
| 1190 | {
|
---|
| 1191 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1192 | reply_thr_get(tcp_fd, EBADMODE, TRUE);
|
---|
| 1193 | return NW_OK;
|
---|
| 1194 | }
|
---|
| 1195 |
|
---|
| 1196 | /* NWTO_SND_URG_MASK */
|
---|
| 1197 | if (!((new_en_flags | new_di_flags) & NWTO_SND_URG_MASK))
|
---|
| 1198 | {
|
---|
| 1199 | new_en_flags |= (old_en_flags & NWTO_SND_URG_MASK);
|
---|
| 1200 | new_di_flags |= (old_di_flags & NWTO_SND_URG_MASK);
|
---|
| 1201 | }
|
---|
| 1202 |
|
---|
| 1203 | /* NWTO_RCV_URG_MASK */
|
---|
| 1204 | if (!((new_en_flags | new_di_flags) & NWTO_RCV_URG_MASK))
|
---|
| 1205 | {
|
---|
| 1206 | new_en_flags |= (old_en_flags & NWTO_RCV_URG_MASK);
|
---|
| 1207 | new_di_flags |= (old_di_flags & NWTO_RCV_URG_MASK);
|
---|
| 1208 | }
|
---|
| 1209 |
|
---|
| 1210 | /* NWTO_BSD_URG_MASK */
|
---|
| 1211 | if (!((new_en_flags | new_di_flags) & NWTO_BSD_URG_MASK))
|
---|
| 1212 | {
|
---|
| 1213 | new_en_flags |= (old_en_flags & NWTO_BSD_URG_MASK);
|
---|
| 1214 | new_di_flags |= (old_di_flags & NWTO_BSD_URG_MASK);
|
---|
| 1215 | }
|
---|
| 1216 | else
|
---|
| 1217 | {
|
---|
| 1218 | if (tcp_fd->tf_conn == NULL)
|
---|
| 1219 | {
|
---|
| 1220 | bf_afree(data);
|
---|
| 1221 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1222 | reply_thr_get(tcp_fd, EINVAL, TRUE);
|
---|
| 1223 | return NW_OK;
|
---|
| 1224 | }
|
---|
| 1225 | }
|
---|
| 1226 |
|
---|
| 1227 | /* NWTO_DEL_RST_MASK */
|
---|
| 1228 | if (!((new_en_flags | new_di_flags) & NWTO_DEL_RST_MASK))
|
---|
| 1229 | {
|
---|
| 1230 | new_en_flags |= (old_en_flags & NWTO_DEL_RST_MASK);
|
---|
| 1231 | new_di_flags |= (old_di_flags & NWTO_DEL_RST_MASK);
|
---|
| 1232 | }
|
---|
| 1233 |
|
---|
| 1234 | /* NWTO_BULK_MASK */
|
---|
| 1235 | if (!((new_en_flags | new_di_flags) & NWTO_BULK_MASK))
|
---|
| 1236 | {
|
---|
| 1237 | new_en_flags |= (old_en_flags & NWTO_BULK_MASK);
|
---|
| 1238 | new_di_flags |= (old_di_flags & NWTO_BULK_MASK);
|
---|
| 1239 | }
|
---|
| 1240 |
|
---|
| 1241 | newopt.nwto_flags= ((unsigned long)new_di_flags << 16) |
|
---|
| 1242 | new_en_flags;
|
---|
| 1243 | tcp_fd->tf_tcpopt= newopt;
|
---|
| 1244 | if (newopt.nwto_flags & NWTO_SND_URG)
|
---|
| 1245 | tcp_fd->tf_flags |= TFF_WR_URG;
|
---|
| 1246 | else
|
---|
| 1247 | tcp_fd->tf_flags &= ~TFF_WR_URG;
|
---|
| 1248 |
|
---|
| 1249 | if (newopt.nwto_flags & NWTO_RCV_URG)
|
---|
| 1250 | tcp_fd->tf_flags |= TFF_RECV_URG;
|
---|
| 1251 | else
|
---|
| 1252 | tcp_fd->tf_flags &= ~TFF_RECV_URG;
|
---|
| 1253 |
|
---|
| 1254 | if (tcp_fd->tf_conn)
|
---|
| 1255 | {
|
---|
| 1256 | if (newopt.nwto_flags & NWTO_BSD_URG)
|
---|
| 1257 | tcp_fd->tf_conn->tc_flags |= TCF_BSD_URG;
|
---|
| 1258 | else
|
---|
| 1259 | tcp_fd->tf_conn->tc_flags &= ~TCF_BSD_URG;
|
---|
| 1260 | }
|
---|
| 1261 |
|
---|
| 1262 | if (newopt.nwto_flags & NWTO_DEL_RST)
|
---|
| 1263 | tcp_fd->tf_flags |= TFF_DEL_RST;
|
---|
| 1264 | else
|
---|
| 1265 | tcp_fd->tf_flags &= ~TFF_DEL_RST;
|
---|
| 1266 |
|
---|
| 1267 | if (newopt.nwto_flags & NWTO_BULK)
|
---|
| 1268 | tcp_fd->tf_flags &= ~TFF_PUSH_DATA;
|
---|
| 1269 | else
|
---|
| 1270 | tcp_fd->tf_flags |= TFF_PUSH_DATA;
|
---|
| 1271 |
|
---|
| 1272 | bf_afree(data);
|
---|
| 1273 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1274 | reply_thr_get(tcp_fd, NW_OK, TRUE);
|
---|
| 1275 | return NW_OK;
|
---|
| 1276 | }
|
---|
| 1277 |
|
---|
| 1278 |
|
---|
| 1279 | PRIVATE tcpport_t find_unused_port(fd)
|
---|
| 1280 | int fd;
|
---|
| 1281 | {
|
---|
| 1282 | tcpport_t port, nw_port;
|
---|
| 1283 |
|
---|
| 1284 | for (port= 0x8000+fd; port < 0xffff-TCP_FD_NR; port+= TCP_FD_NR)
|
---|
| 1285 | {
|
---|
| 1286 | nw_port= htons(port);
|
---|
| 1287 | if (is_unused_port(nw_port))
|
---|
| 1288 | return nw_port;
|
---|
| 1289 | }
|
---|
| 1290 | for (port= 0x8000; port < 0xffff; port++)
|
---|
| 1291 | {
|
---|
| 1292 | nw_port= htons(port);
|
---|
| 1293 | if (is_unused_port(nw_port))
|
---|
| 1294 | return nw_port;
|
---|
| 1295 | }
|
---|
| 1296 | ip_panic(( "unable to find unused port (shouldn't occur)" ));
|
---|
| 1297 | return 0;
|
---|
| 1298 | }
|
---|
| 1299 |
|
---|
| 1300 | PRIVATE int is_unused_port(port)
|
---|
| 1301 | tcpport_t port;
|
---|
| 1302 | {
|
---|
| 1303 | int i;
|
---|
| 1304 | tcp_fd_t *tcp_fd;
|
---|
| 1305 | tcp_conn_t *tcp_conn;
|
---|
| 1306 |
|
---|
| 1307 | for (i= 0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++,
|
---|
| 1308 | tcp_fd++)
|
---|
| 1309 | {
|
---|
| 1310 | if (!(tcp_fd->tf_flags & TFF_CONF_SET))
|
---|
| 1311 | continue;
|
---|
| 1312 | if (tcp_fd->tf_tcpconf.nwtc_locport == port)
|
---|
| 1313 | return FALSE;
|
---|
| 1314 | }
|
---|
| 1315 | for (i= tcp_conf_nr, tcp_conn= tcp_conn_table+i;
|
---|
| 1316 | i<TCP_CONN_NR; i++, tcp_conn++)
|
---|
| 1317 | /* the first tcp_conf_nr ports are special */
|
---|
| 1318 | {
|
---|
| 1319 | if (!(tcp_conn->tc_flags & TCF_INUSE))
|
---|
| 1320 | continue;
|
---|
| 1321 | if (tcp_conn->tc_locport == port)
|
---|
| 1322 | return FALSE;
|
---|
| 1323 | }
|
---|
| 1324 | return TRUE;
|
---|
| 1325 | }
|
---|
| 1326 |
|
---|
| 1327 | PRIVATE int reply_thr_put(tcp_fd, reply, for_ioctl)
|
---|
| 1328 | tcp_fd_t *tcp_fd;
|
---|
| 1329 | int reply;
|
---|
| 1330 | int for_ioctl;
|
---|
| 1331 | {
|
---|
| 1332 | assert (tcp_fd);
|
---|
| 1333 |
|
---|
| 1334 | return (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd, reply,
|
---|
| 1335 | (acc_t *)0, for_ioctl);
|
---|
| 1336 | }
|
---|
| 1337 |
|
---|
| 1338 | PRIVATE void reply_thr_get(tcp_fd, reply, for_ioctl)
|
---|
| 1339 | tcp_fd_t *tcp_fd;
|
---|
| 1340 | int reply;
|
---|
| 1341 | int for_ioctl;
|
---|
| 1342 | {
|
---|
| 1343 | acc_t *result;
|
---|
| 1344 |
|
---|
| 1345 | result= (*tcp_fd->tf_get_userdata)(tcp_fd->tf_srfd, reply,
|
---|
| 1346 | (size_t)0, for_ioctl);
|
---|
| 1347 | assert (!result);
|
---|
| 1348 | }
|
---|
| 1349 |
|
---|
| 1350 | PUBLIC int tcp_su4listen(tcp_fd, tcp_conn, do_listenq)
|
---|
| 1351 | tcp_fd_t *tcp_fd;
|
---|
| 1352 | tcp_conn_t *tcp_conn;
|
---|
| 1353 | int do_listenq;
|
---|
| 1354 | {
|
---|
| 1355 | tcp_conn->tc_locport= tcp_fd->tf_tcpconf.nwtc_locport;
|
---|
| 1356 | tcp_conn->tc_locaddr= tcp_fd->tf_port->tp_ipaddr;
|
---|
| 1357 | if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP)
|
---|
| 1358 | tcp_conn->tc_remport= tcp_fd->tf_tcpconf.nwtc_remport;
|
---|
| 1359 | else
|
---|
| 1360 | tcp_conn->tc_remport= 0;
|
---|
| 1361 | if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA)
|
---|
| 1362 | tcp_conn->tc_remaddr= tcp_fd->tf_tcpconf.nwtc_remaddr;
|
---|
| 1363 | else
|
---|
| 1364 | tcp_conn->tc_remaddr= 0;
|
---|
| 1365 |
|
---|
| 1366 | tcp_setup_conn(tcp_fd->tf_port, tcp_conn);
|
---|
| 1367 | tcp_conn->tc_fd= tcp_fd;
|
---|
| 1368 | tcp_conn->tc_connInprogress= 1;
|
---|
| 1369 | tcp_conn->tc_orglisten= TRUE;
|
---|
| 1370 | tcp_conn->tc_state= TCS_LISTEN;
|
---|
| 1371 | tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_LISTEN;
|
---|
| 1372 | if (do_listenq)
|
---|
| 1373 | {
|
---|
| 1374 | tcp_fd->tf_flags |= TFF_LISTENQ;
|
---|
| 1375 | tcp_reply_ioctl(tcp_fd, NW_OK);
|
---|
| 1376 | return NW_OK;
|
---|
| 1377 | }
|
---|
| 1378 | return NW_SUSPEND;
|
---|
| 1379 | }
|
---|
| 1380 |
|
---|
| 1381 | /*
|
---|
| 1382 | find_empty_conn
|
---|
| 1383 |
|
---|
| 1384 | This function returns a connection that is not inuse.
|
---|
| 1385 | This includes connections that are never used, and connections without a
|
---|
| 1386 | user that are not used for a while.
|
---|
| 1387 | */
|
---|
| 1388 |
|
---|
| 1389 | PRIVATE tcp_conn_t *find_empty_conn()
|
---|
| 1390 | {
|
---|
| 1391 | int i;
|
---|
| 1392 | tcp_conn_t *tcp_conn;
|
---|
| 1393 |
|
---|
| 1394 | for (i=tcp_conf_nr, tcp_conn= tcp_conn_table+i;
|
---|
| 1395 | i<TCP_CONN_NR; i++, tcp_conn++)
|
---|
| 1396 | /* the first tcp_conf_nr connections are reserved for
|
---|
| 1397 | * RSTs
|
---|
| 1398 | */
|
---|
| 1399 | {
|
---|
| 1400 | if (tcp_conn->tc_flags == TCF_EMPTY)
|
---|
| 1401 | {
|
---|
| 1402 | tcp_conn->tc_connInprogress= 0;
|
---|
| 1403 | tcp_conn->tc_fd= NULL;
|
---|
| 1404 | return tcp_conn;
|
---|
| 1405 | }
|
---|
| 1406 | if (tcp_conn->tc_fd)
|
---|
| 1407 | continue;
|
---|
| 1408 | if (tcp_conn->tc_senddis > get_time())
|
---|
| 1409 | continue;
|
---|
| 1410 | if (tcp_conn->tc_state != TCS_CLOSED)
|
---|
| 1411 | {
|
---|
| 1412 | tcp_close_connection (tcp_conn, ENOCONN);
|
---|
| 1413 | }
|
---|
| 1414 | tcp_conn->tc_flags= 0;
|
---|
| 1415 | return tcp_conn;
|
---|
| 1416 | }
|
---|
| 1417 | return NULL;
|
---|
| 1418 | }
|
---|
| 1419 |
|
---|
| 1420 |
|
---|
| 1421 | /*
|
---|
| 1422 | find_conn_entry
|
---|
| 1423 |
|
---|
| 1424 | This function return a connection matching locport, locaddr, remport, remaddr.
|
---|
| 1425 | If no such connection exists NULL is returned.
|
---|
| 1426 | If a connection exists without mainuser it is closed.
|
---|
| 1427 | */
|
---|
| 1428 |
|
---|
| 1429 | PRIVATE tcp_conn_t *find_conn_entry(locport, locaddr, remport, remaddr)
|
---|
| 1430 | tcpport_t locport;
|
---|
| 1431 | ipaddr_t locaddr;
|
---|
| 1432 | tcpport_t remport;
|
---|
| 1433 | ipaddr_t remaddr;
|
---|
| 1434 | {
|
---|
| 1435 | tcp_conn_t *tcp_conn;
|
---|
| 1436 | int i, state;
|
---|
| 1437 |
|
---|
| 1438 | assert(remport);
|
---|
| 1439 | assert(remaddr);
|
---|
| 1440 | for (i=tcp_conf_nr, tcp_conn= tcp_conn_table+i; i<TCP_CONN_NR;
|
---|
| 1441 | i++, tcp_conn++)
|
---|
| 1442 | /* the first tcp_conf_nr connections are reserved for
|
---|
| 1443 | RSTs */
|
---|
| 1444 | {
|
---|
| 1445 | if (tcp_conn->tc_flags == TCF_EMPTY)
|
---|
| 1446 | continue;
|
---|
| 1447 | if (tcp_conn->tc_locport != locport ||
|
---|
| 1448 | tcp_conn->tc_locaddr != locaddr ||
|
---|
| 1449 | tcp_conn->tc_remport != remport ||
|
---|
| 1450 | tcp_conn->tc_remaddr != remaddr)
|
---|
| 1451 | continue;
|
---|
| 1452 | if (tcp_conn->tc_fd)
|
---|
| 1453 | return tcp_conn;
|
---|
| 1454 | state= tcp_conn->tc_state;
|
---|
| 1455 | if (state != TCS_CLOSED)
|
---|
| 1456 | {
|
---|
| 1457 | tcp_close_connection(tcp_conn, ENOCONN);
|
---|
| 1458 | }
|
---|
| 1459 | return tcp_conn;
|
---|
| 1460 | }
|
---|
| 1461 | return NULL;
|
---|
| 1462 | }
|
---|
| 1463 |
|
---|
| 1464 | PRIVATE void read_ip_packets(tcp_port)
|
---|
| 1465 | tcp_port_t *tcp_port;
|
---|
| 1466 | {
|
---|
| 1467 | int result;
|
---|
| 1468 |
|
---|
| 1469 | do
|
---|
| 1470 | {
|
---|
| 1471 | tcp_port->tp_flags |= TPF_READ_IP;
|
---|
| 1472 | result= ip_read(tcp_port->tp_ipfd, TCP_MAX_DATAGRAM);
|
---|
| 1473 | if (result == NW_SUSPEND)
|
---|
| 1474 | {
|
---|
| 1475 | tcp_port->tp_flags |= TPF_READ_SP;
|
---|
| 1476 | return;
|
---|
| 1477 | }
|
---|
| 1478 | assert(result == NW_OK);
|
---|
| 1479 | tcp_port->tp_flags &= ~TPF_READ_IP;
|
---|
| 1480 | } while(!(tcp_port->tp_flags & TPF_READ_IP));
|
---|
| 1481 | }
|
---|
| 1482 |
|
---|
| 1483 | /*
|
---|
| 1484 | find_best_conn
|
---|
| 1485 | */
|
---|
| 1486 |
|
---|
| 1487 | PRIVATE tcp_conn_t *find_best_conn(ip_hdr, tcp_hdr)
|
---|
| 1488 | ip_hdr_t *ip_hdr;
|
---|
| 1489 | tcp_hdr_t *tcp_hdr;
|
---|
| 1490 | {
|
---|
| 1491 |
|
---|
| 1492 | int best_level, new_level;
|
---|
| 1493 | tcp_conn_t *best_conn, *listen_conn, *tcp_conn;
|
---|
| 1494 | tcp_fd_t *tcp_fd;
|
---|
| 1495 | int i;
|
---|
| 1496 | ipaddr_t locaddr;
|
---|
| 1497 | ipaddr_t remaddr;
|
---|
| 1498 | tcpport_t locport;
|
---|
| 1499 | tcpport_t remport;
|
---|
| 1500 |
|
---|
| 1501 | locaddr= ip_hdr->ih_dst;
|
---|
| 1502 | remaddr= ip_hdr->ih_src;
|
---|
| 1503 | locport= tcp_hdr->th_dstport;
|
---|
| 1504 | remport= tcp_hdr->th_srcport;
|
---|
| 1505 | if (!remport) /* This can interfere with a listen, so we reject it
|
---|
| 1506 | * by clearing the requested port
|
---|
| 1507 | */
|
---|
| 1508 | locport= 0;
|
---|
| 1509 |
|
---|
| 1510 | best_level= 0;
|
---|
| 1511 | best_conn= NULL;
|
---|
| 1512 | listen_conn= NULL;
|
---|
| 1513 | for (i= tcp_conf_nr, tcp_conn= tcp_conn_table+i;
|
---|
| 1514 | i<TCP_CONN_NR; i++, tcp_conn++)
|
---|
| 1515 | /* the first tcp_conf_nr connections are reserved for
|
---|
| 1516 | RSTs */
|
---|
| 1517 | {
|
---|
| 1518 | if (!(tcp_conn->tc_flags & TCF_INUSE))
|
---|
| 1519 | continue;
|
---|
| 1520 | /* First fast check for open connections. */
|
---|
| 1521 | if (tcp_conn->tc_locaddr == locaddr &&
|
---|
| 1522 | tcp_conn->tc_locport == locport &&
|
---|
| 1523 | tcp_conn->tc_remport == remport &&
|
---|
| 1524 | tcp_conn->tc_remaddr == remaddr &&
|
---|
| 1525 | tcp_conn->tc_fd)
|
---|
| 1526 | {
|
---|
| 1527 | return tcp_conn;
|
---|
| 1528 | }
|
---|
| 1529 |
|
---|
| 1530 | /* Now check for listens and abandoned connections. */
|
---|
| 1531 | if (tcp_conn->tc_locaddr != locaddr)
|
---|
| 1532 | {
|
---|
| 1533 | continue;
|
---|
| 1534 | }
|
---|
| 1535 | new_level= 0;
|
---|
| 1536 | if (tcp_conn->tc_locport)
|
---|
| 1537 | {
|
---|
| 1538 | if (tcp_conn->tc_locport != locport)
|
---|
| 1539 | {
|
---|
| 1540 | continue;
|
---|
| 1541 | }
|
---|
| 1542 | new_level += 4;
|
---|
| 1543 | }
|
---|
| 1544 | if (tcp_conn->tc_remport)
|
---|
| 1545 | {
|
---|
| 1546 | if (tcp_conn->tc_remport != remport)
|
---|
| 1547 | {
|
---|
| 1548 | continue;
|
---|
| 1549 | }
|
---|
| 1550 | new_level += 1;
|
---|
| 1551 | }
|
---|
| 1552 | if (tcp_conn->tc_remaddr)
|
---|
| 1553 | {
|
---|
| 1554 | if (tcp_conn->tc_remaddr != remaddr)
|
---|
| 1555 | {
|
---|
| 1556 | continue;
|
---|
| 1557 | }
|
---|
| 1558 | new_level += 2;
|
---|
| 1559 | }
|
---|
| 1560 | if (new_level<best_level)
|
---|
| 1561 | continue;
|
---|
| 1562 | if (new_level != 7 && tcp_conn->tc_state != TCS_LISTEN)
|
---|
| 1563 | continue;
|
---|
| 1564 | if (new_level == 7)
|
---|
| 1565 | /* We found an abandoned connection */
|
---|
| 1566 | {
|
---|
| 1567 | assert(!tcp_conn->tc_fd);
|
---|
| 1568 | if (best_conn && tcp_Lmod4G(tcp_conn->tc_ISS,
|
---|
| 1569 | best_conn->tc_ISS))
|
---|
| 1570 | {
|
---|
| 1571 | continue;
|
---|
| 1572 | }
|
---|
| 1573 | best_conn= tcp_conn;
|
---|
| 1574 | continue;
|
---|
| 1575 | }
|
---|
| 1576 | if (!(tcp_hdr->th_flags & THF_SYN))
|
---|
| 1577 | continue;
|
---|
| 1578 | best_level= new_level;
|
---|
| 1579 | listen_conn= tcp_conn;
|
---|
| 1580 | assert(listen_conn->tc_fd != NULL);
|
---|
| 1581 | }
|
---|
| 1582 |
|
---|
| 1583 | if (listen_conn && listen_conn->tc_fd->tf_flags & TFF_LISTENQ &&
|
---|
| 1584 | listen_conn->tc_fd->tf_conn == listen_conn)
|
---|
| 1585 | {
|
---|
| 1586 | /* Special processing for listen queues. Only accept the
|
---|
| 1587 | * connection if there is empty space in the queue and
|
---|
| 1588 | * there are empty connections as well.
|
---|
| 1589 | */
|
---|
| 1590 | listen_conn= new_conn_for_queue(listen_conn->tc_fd);
|
---|
| 1591 | }
|
---|
| 1592 |
|
---|
| 1593 | if (!best_conn && !listen_conn)
|
---|
| 1594 | {
|
---|
| 1595 | if ((tcp_hdr->th_flags & THF_SYN) &&
|
---|
| 1596 | maybe_listen(locaddr, locport, remaddr, remport))
|
---|
| 1597 | {
|
---|
| 1598 | /* Quick hack to implement listen back logs:
|
---|
| 1599 | * if a SYN arrives and there is no listen waiting
|
---|
| 1600 | * for that packet, then no reply is sent.
|
---|
| 1601 | */
|
---|
| 1602 | return NULL;
|
---|
| 1603 | }
|
---|
| 1604 |
|
---|
| 1605 | for (i=0, tcp_conn= tcp_conn_table; i<tcp_conf_nr;
|
---|
| 1606 | i++, tcp_conn++)
|
---|
| 1607 | {
|
---|
| 1608 | /* find valid port to send RST */
|
---|
| 1609 | if ((tcp_conn->tc_flags & TCF_INUSE) &&
|
---|
| 1610 | tcp_conn->tc_locaddr==locaddr)
|
---|
| 1611 | {
|
---|
| 1612 | break;
|
---|
| 1613 | }
|
---|
| 1614 | }
|
---|
| 1615 | assert (tcp_conn);
|
---|
| 1616 | assert (tcp_conn->tc_state == TCS_CLOSED);
|
---|
| 1617 |
|
---|
| 1618 | tcp_conn->tc_locport= locport;
|
---|
| 1619 | tcp_conn->tc_locaddr= locaddr;
|
---|
| 1620 | tcp_conn->tc_remport= remport;
|
---|
| 1621 | tcp_conn->tc_remaddr= remaddr;
|
---|
| 1622 | assert (!tcp_conn->tc_fd);
|
---|
| 1623 | return tcp_conn;
|
---|
| 1624 | }
|
---|
| 1625 |
|
---|
| 1626 | if (best_conn)
|
---|
| 1627 | {
|
---|
| 1628 | if (!listen_conn)
|
---|
| 1629 | {
|
---|
| 1630 | assert(!best_conn->tc_fd);
|
---|
| 1631 | return best_conn;
|
---|
| 1632 | }
|
---|
| 1633 |
|
---|
| 1634 | assert(listen_conn->tc_connInprogress);
|
---|
| 1635 | tcp_fd= listen_conn->tc_fd;
|
---|
| 1636 | assert(tcp_fd);
|
---|
| 1637 | assert((tcp_fd->tf_flags & TFF_LISTENQ) ||
|
---|
| 1638 | tcp_fd->tf_conn == listen_conn);
|
---|
| 1639 |
|
---|
| 1640 | if (best_conn->tc_state != TCS_CLOSED)
|
---|
| 1641 | tcp_close_connection(best_conn, ENOCONN);
|
---|
| 1642 |
|
---|
| 1643 | listen_conn->tc_ISS= best_conn->tc_ISS;
|
---|
| 1644 | if (best_conn->tc_senddis > listen_conn->tc_senddis)
|
---|
| 1645 | listen_conn->tc_senddis= best_conn->tc_senddis;
|
---|
| 1646 | return listen_conn;
|
---|
| 1647 | }
|
---|
| 1648 | assert (listen_conn);
|
---|
| 1649 | return listen_conn;
|
---|
| 1650 | }
|
---|
| 1651 |
|
---|
| 1652 | /*
|
---|
| 1653 | new_conn_for_queue
|
---|
| 1654 | */
|
---|
| 1655 | PRIVATE tcp_conn_t *new_conn_for_queue(tcp_fd)
|
---|
| 1656 | tcp_fd_t *tcp_fd;
|
---|
| 1657 | {
|
---|
| 1658 | int i;
|
---|
| 1659 | tcp_conn_t *tcp_conn;
|
---|
| 1660 |
|
---|
| 1661 | assert(tcp_fd->tf_flags & TFF_LISTENQ);
|
---|
| 1662 |
|
---|
| 1663 | for (i= 0; i<TFL_LISTEN_MAX; i++)
|
---|
| 1664 | {
|
---|
| 1665 | if (tcp_fd->tf_listenq[i] == NULL)
|
---|
| 1666 | break;
|
---|
| 1667 | }
|
---|
| 1668 | if (i >= TFL_LISTEN_MAX)
|
---|
| 1669 | return NULL;
|
---|
| 1670 |
|
---|
| 1671 | tcp_conn= find_empty_conn();
|
---|
| 1672 | if (!tcp_conn)
|
---|
| 1673 | return NULL;
|
---|
| 1674 | tcp_fd->tf_listenq[i]= tcp_conn;
|
---|
| 1675 | (void)tcp_su4listen(tcp_fd, tcp_conn, 0 /* !do_listenq */);
|
---|
| 1676 | return tcp_conn;
|
---|
| 1677 | }
|
---|
| 1678 |
|
---|
| 1679 | /*
|
---|
| 1680 | maybe_listen
|
---|
| 1681 | */
|
---|
| 1682 | PRIVATE int maybe_listen(locaddr, locport, remaddr, remport)
|
---|
| 1683 | ipaddr_t locaddr;
|
---|
| 1684 | tcpport_t locport;
|
---|
| 1685 | ipaddr_t remaddr;
|
---|
| 1686 | tcpport_t remport;
|
---|
| 1687 | {
|
---|
| 1688 | int i;
|
---|
| 1689 | tcp_conn_t *tcp_conn;
|
---|
| 1690 | tcp_fd_t *fd;
|
---|
| 1691 |
|
---|
| 1692 | for (i= tcp_conf_nr, tcp_conn= tcp_conn_table+i;
|
---|
| 1693 | i<TCP_CONN_NR; i++, tcp_conn++)
|
---|
| 1694 | {
|
---|
| 1695 | if (!(tcp_conn->tc_flags & TCF_INUSE))
|
---|
| 1696 | continue;
|
---|
| 1697 |
|
---|
| 1698 | if (tcp_conn->tc_locaddr != locaddr)
|
---|
| 1699 | {
|
---|
| 1700 | continue;
|
---|
| 1701 | }
|
---|
| 1702 | if (tcp_conn->tc_locport != locport )
|
---|
| 1703 | {
|
---|
| 1704 | continue;
|
---|
| 1705 | }
|
---|
| 1706 | if (!tcp_conn->tc_orglisten)
|
---|
| 1707 | continue;
|
---|
| 1708 | fd= tcp_conn->tc_fd;
|
---|
| 1709 | if (!fd)
|
---|
| 1710 | continue;
|
---|
| 1711 | if ((fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP) &&
|
---|
| 1712 | tcp_conn->tc_remport != remport)
|
---|
| 1713 | {
|
---|
| 1714 | continue;
|
---|
| 1715 | }
|
---|
| 1716 | if ((fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA) &&
|
---|
| 1717 | tcp_conn->tc_remaddr != remaddr)
|
---|
| 1718 | {
|
---|
| 1719 | continue;
|
---|
| 1720 | }
|
---|
| 1721 | if (!(fd->tf_flags & TFF_DEL_RST))
|
---|
| 1722 | continue;
|
---|
| 1723 | return 1;
|
---|
| 1724 |
|
---|
| 1725 | }
|
---|
| 1726 | return 0;
|
---|
| 1727 | }
|
---|
| 1728 |
|
---|
| 1729 |
|
---|
| 1730 | PUBLIC void tcp_reply_ioctl(tcp_fd, reply)
|
---|
| 1731 | tcp_fd_t *tcp_fd;
|
---|
| 1732 | int reply;
|
---|
| 1733 | {
|
---|
| 1734 | assert (tcp_fd->tf_flags & TFF_IOCTL_IP);
|
---|
| 1735 | assert (tcp_fd->tf_ioreq == NWIOTCPSHUTDOWN ||
|
---|
| 1736 | tcp_fd->tf_ioreq == NWIOTCPLISTEN ||
|
---|
| 1737 | tcp_fd->tf_ioreq == NWIOTCPLISTENQ ||
|
---|
| 1738 | tcp_fd->tf_ioreq == NWIOTCPACCEPTTO ||
|
---|
| 1739 | tcp_fd->tf_ioreq == NWIOTCPCONN);
|
---|
| 1740 |
|
---|
| 1741 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 1742 | reply_thr_get (tcp_fd, reply, TRUE);
|
---|
| 1743 | }
|
---|
| 1744 |
|
---|
| 1745 | PUBLIC void tcp_reply_write(tcp_fd, reply)
|
---|
| 1746 | tcp_fd_t *tcp_fd;
|
---|
| 1747 | size_t reply;
|
---|
| 1748 | {
|
---|
| 1749 | assert (tcp_fd->tf_flags & TFF_WRITE_IP);
|
---|
| 1750 |
|
---|
| 1751 | tcp_fd->tf_flags &= ~TFF_WRITE_IP;
|
---|
| 1752 | reply_thr_get (tcp_fd, reply, FALSE);
|
---|
| 1753 | }
|
---|
| 1754 |
|
---|
| 1755 | PUBLIC void tcp_reply_read(tcp_fd, reply)
|
---|
| 1756 | tcp_fd_t *tcp_fd;
|
---|
| 1757 | size_t reply;
|
---|
| 1758 | {
|
---|
| 1759 | assert (tcp_fd->tf_flags & TFF_READ_IP);
|
---|
| 1760 |
|
---|
| 1761 | tcp_fd->tf_flags &= ~TFF_READ_IP;
|
---|
| 1762 | reply_thr_put (tcp_fd, reply, FALSE);
|
---|
| 1763 | }
|
---|
| 1764 |
|
---|
| 1765 | PUBLIC int tcp_write(fd, count)
|
---|
| 1766 | int fd;
|
---|
| 1767 | size_t count;
|
---|
| 1768 | {
|
---|
| 1769 | tcp_fd_t *tcp_fd;
|
---|
| 1770 | tcp_conn_t *tcp_conn;
|
---|
| 1771 |
|
---|
| 1772 | tcp_fd= &tcp_fd_table[fd];
|
---|
| 1773 |
|
---|
| 1774 | assert (tcp_fd->tf_flags & TFF_INUSE);
|
---|
| 1775 |
|
---|
| 1776 | if (!(tcp_fd->tf_flags & TFF_CONNECTED))
|
---|
| 1777 | {
|
---|
| 1778 | reply_thr_get (tcp_fd, ENOTCONN, FALSE);
|
---|
| 1779 | return NW_OK;
|
---|
| 1780 | }
|
---|
| 1781 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 1782 | if (tcp_conn->tc_state == TCS_CLOSED)
|
---|
| 1783 | {
|
---|
| 1784 | reply_thr_get(tcp_fd, tcp_conn->tc_error, FALSE);
|
---|
| 1785 | return NW_OK;
|
---|
| 1786 | }
|
---|
| 1787 | if (tcp_conn->tc_flags & TCF_FIN_SENT)
|
---|
| 1788 | {
|
---|
| 1789 | reply_thr_get (tcp_fd, ESHUTDOWN, FALSE);
|
---|
| 1790 | return NW_OK;
|
---|
| 1791 | }
|
---|
| 1792 |
|
---|
| 1793 | tcp_fd->tf_flags |= TFF_WRITE_IP;
|
---|
| 1794 | tcp_fd->tf_write_offset= 0;
|
---|
| 1795 | tcp_fd->tf_write_count= count;
|
---|
| 1796 |
|
---|
| 1797 | /* New data may cause a segment to be sent. Clear PUSH_NOW
|
---|
| 1798 | * from last NWIOTCPPUSH ioctl.
|
---|
| 1799 | */
|
---|
| 1800 | tcp_conn->tc_flags &= ~(TCF_NO_PUSH|TCF_PUSH_NOW);
|
---|
| 1801 |
|
---|
| 1802 | /* Start the timer (if necessary) */
|
---|
| 1803 | if (tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_UNA)
|
---|
| 1804 | tcp_set_send_timer(tcp_conn);
|
---|
| 1805 |
|
---|
| 1806 | assert(tcp_conn->tc_busy == 0);
|
---|
| 1807 | tcp_conn->tc_busy++;
|
---|
| 1808 | tcp_fd_write(tcp_conn);
|
---|
| 1809 | tcp_conn->tc_busy--;
|
---|
| 1810 | tcp_conn_write(tcp_conn, 0);
|
---|
| 1811 |
|
---|
| 1812 | if (!(tcp_fd->tf_flags & TFF_WRITE_IP))
|
---|
| 1813 | return NW_OK;
|
---|
| 1814 | else
|
---|
| 1815 | return NW_SUSPEND;
|
---|
| 1816 | }
|
---|
| 1817 |
|
---|
| 1818 | PUBLIC int
|
---|
| 1819 | tcp_read(fd, count)
|
---|
| 1820 | int fd;
|
---|
| 1821 | size_t count;
|
---|
| 1822 | {
|
---|
| 1823 | tcp_fd_t *tcp_fd;
|
---|
| 1824 | tcp_conn_t *tcp_conn;
|
---|
| 1825 |
|
---|
| 1826 | tcp_fd= &tcp_fd_table[fd];
|
---|
| 1827 |
|
---|
| 1828 | assert (tcp_fd->tf_flags & TFF_INUSE);
|
---|
| 1829 |
|
---|
| 1830 | if (!(tcp_fd->tf_flags & TFF_CONNECTED))
|
---|
| 1831 | {
|
---|
| 1832 | reply_thr_put (tcp_fd, ENOTCONN, FALSE);
|
---|
| 1833 | return NW_OK;
|
---|
| 1834 | }
|
---|
| 1835 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 1836 |
|
---|
| 1837 | tcp_fd->tf_flags |= TFF_READ_IP;
|
---|
| 1838 | tcp_fd->tf_read_offset= 0;
|
---|
| 1839 | tcp_fd->tf_read_count= count;
|
---|
| 1840 |
|
---|
| 1841 | assert(tcp_conn->tc_busy == 0);
|
---|
| 1842 | tcp_conn->tc_busy++;
|
---|
| 1843 | tcp_fd_read(tcp_conn, 0);
|
---|
| 1844 | tcp_conn->tc_busy--;
|
---|
| 1845 | if (!(tcp_fd->tf_flags & TFF_READ_IP))
|
---|
| 1846 | return NW_OK;
|
---|
| 1847 | else
|
---|
| 1848 | return NW_SUSPEND;
|
---|
| 1849 | }
|
---|
| 1850 |
|
---|
| 1851 | /*
|
---|
| 1852 | tcp_restart_connect
|
---|
| 1853 |
|
---|
| 1854 | reply the success or failure of a connect to the user.
|
---|
| 1855 | */
|
---|
| 1856 |
|
---|
| 1857 |
|
---|
| 1858 | PUBLIC void tcp_restart_connect(tcp_conn)
|
---|
| 1859 | tcp_conn_t *tcp_conn;
|
---|
| 1860 | {
|
---|
| 1861 | tcp_fd_t *tcp_fd;
|
---|
| 1862 | int reply;
|
---|
| 1863 |
|
---|
| 1864 | assert(tcp_conn->tc_connInprogress);
|
---|
| 1865 | tcp_conn->tc_connInprogress= 0;
|
---|
| 1866 |
|
---|
| 1867 | tcp_fd= tcp_conn->tc_fd;
|
---|
| 1868 | assert(tcp_fd);
|
---|
| 1869 | if (tcp_fd->tf_flags & TFF_LISTENQ)
|
---|
| 1870 | {
|
---|
| 1871 | /* Special code for listen queues */
|
---|
| 1872 | assert(tcp_conn->tc_state != TCS_CLOSED);
|
---|
| 1873 |
|
---|
| 1874 | /* Reply for select */
|
---|
| 1875 | if ((tcp_fd->tf_flags & TFF_SEL_READ) &&
|
---|
| 1876 | tcp_fd->tf_select_res)
|
---|
| 1877 | {
|
---|
| 1878 | tcp_fd->tf_flags &= ~TFF_SEL_READ;
|
---|
| 1879 | tcp_fd->tf_select_res(tcp_fd->tf_srfd,
|
---|
| 1880 | SR_SELECT_READ);
|
---|
| 1881 | }
|
---|
| 1882 |
|
---|
| 1883 | /* Reply for acceptto */
|
---|
| 1884 | if (tcp_fd->tf_flags & TFF_IOCTL_IP)
|
---|
| 1885 | (void) tcp_acceptto(tcp_fd);
|
---|
| 1886 |
|
---|
| 1887 | return;
|
---|
| 1888 | }
|
---|
| 1889 |
|
---|
| 1890 | if (tcp_conn->tc_state == TCS_CLOSED)
|
---|
| 1891 | {
|
---|
| 1892 | reply= tcp_conn->tc_error;
|
---|
| 1893 | assert(tcp_conn->tc_fd == tcp_fd);
|
---|
| 1894 | tcp_fd->tf_conn= NULL;
|
---|
| 1895 | tcp_conn->tc_fd= NULL;
|
---|
| 1896 | tcp_fd->tf_error= reply;
|
---|
| 1897 | }
|
---|
| 1898 | else
|
---|
| 1899 | {
|
---|
| 1900 | tcp_fd->tf_flags |= TFF_CONNECTED;
|
---|
| 1901 | reply= NW_OK;
|
---|
| 1902 | }
|
---|
| 1903 |
|
---|
| 1904 | if (tcp_fd->tf_flags & TFF_CONNECTING)
|
---|
| 1905 | {
|
---|
| 1906 | /* Special code for asynchronous connects */
|
---|
| 1907 | tcp_fd->tf_flags &= ~TFF_CONNECTING;
|
---|
| 1908 |
|
---|
| 1909 | /* Reply for select */
|
---|
| 1910 | if ((tcp_fd->tf_flags & TFF_SEL_WRITE) &&
|
---|
| 1911 | tcp_fd->tf_select_res)
|
---|
| 1912 | {
|
---|
| 1913 | tcp_fd->tf_flags &= ~TFF_SEL_WRITE;
|
---|
| 1914 | tcp_fd->tf_select_res(tcp_fd->tf_srfd,
|
---|
| 1915 | SR_SELECT_WRITE);
|
---|
| 1916 | }
|
---|
| 1917 |
|
---|
| 1918 | return;
|
---|
| 1919 | }
|
---|
| 1920 |
|
---|
| 1921 | assert(tcp_fd->tf_flags & TFF_IOCTL_IP);
|
---|
| 1922 | assert(tcp_fd->tf_ioreq == NWIOTCPLISTEN ||
|
---|
| 1923 | tcp_fd->tf_ioreq == NWIOTCPCONN);
|
---|
| 1924 |
|
---|
| 1925 | tcp_reply_ioctl (tcp_fd, reply);
|
---|
| 1926 | }
|
---|
| 1927 |
|
---|
| 1928 | /*
|
---|
| 1929 | tcp_close
|
---|
| 1930 | */
|
---|
| 1931 |
|
---|
| 1932 | PUBLIC void tcp_close(fd)
|
---|
| 1933 | int fd;
|
---|
| 1934 | {
|
---|
| 1935 | int i;
|
---|
| 1936 | tcp_fd_t *tcp_fd;
|
---|
| 1937 | tcp_conn_t *tcp_conn;
|
---|
| 1938 |
|
---|
| 1939 | tcp_fd= &tcp_fd_table[fd];
|
---|
| 1940 |
|
---|
| 1941 | assert (tcp_fd->tf_flags & TFF_INUSE);
|
---|
| 1942 | assert (!(tcp_fd->tf_flags &
|
---|
| 1943 | (TFF_IOCTL_IP|TFF_READ_IP|TFF_WRITE_IP)));
|
---|
| 1944 |
|
---|
| 1945 | if (tcp_fd->tf_flags & TFF_LISTENQ)
|
---|
| 1946 | {
|
---|
| 1947 | /* Special code for listen queues */
|
---|
| 1948 | for (i= 0; i<TFL_LISTEN_MAX; i++)
|
---|
| 1949 | {
|
---|
| 1950 | tcp_conn= tcp_fd->tf_listenq[i];
|
---|
| 1951 | if (!tcp_conn)
|
---|
| 1952 | continue;
|
---|
| 1953 |
|
---|
| 1954 | tcp_fd->tf_listenq[i]= NULL;
|
---|
| 1955 | assert(tcp_conn->tc_fd == tcp_fd);
|
---|
| 1956 | tcp_conn->tc_fd= NULL;
|
---|
| 1957 |
|
---|
| 1958 | if (tcp_conn->tc_connInprogress)
|
---|
| 1959 | {
|
---|
| 1960 | tcp_conn->tc_connInprogress= 0;
|
---|
| 1961 | tcp_close_connection(tcp_conn, ENOCONN);
|
---|
| 1962 | continue;
|
---|
| 1963 | }
|
---|
| 1964 |
|
---|
| 1965 | tcp_shutdown (tcp_conn);
|
---|
| 1966 | if (tcp_conn->tc_state == TCS_ESTABLISHED)
|
---|
| 1967 | tcp_conn->tc_state= TCS_CLOSING;
|
---|
| 1968 |
|
---|
| 1969 | /* Set the retransmission timeout a bit smaller. */
|
---|
| 1970 | tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_CLOSING;
|
---|
| 1971 |
|
---|
| 1972 | /* If all data has been acknowledged, close the connection. */
|
---|
| 1973 | if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
|
---|
| 1974 | tcp_close_connection(tcp_conn, ENOTCONN);
|
---|
| 1975 | }
|
---|
| 1976 |
|
---|
| 1977 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 1978 | assert(tcp_conn->tc_fd == tcp_fd);
|
---|
| 1979 | assert (tcp_conn->tc_connInprogress);
|
---|
| 1980 | tcp_conn->tc_connInprogress= 0;
|
---|
| 1981 | tcp_conn->tc_fd= NULL;
|
---|
| 1982 | tcp_fd->tf_conn= NULL;
|
---|
| 1983 | tcp_close_connection(tcp_conn, ENOCONN);
|
---|
| 1984 | }
|
---|
| 1985 | for (i= 0; i<TFL_LISTEN_MAX; i++)
|
---|
| 1986 | {
|
---|
| 1987 | assert(tcp_fd->tf_listenq[i] == NULL);
|
---|
| 1988 | }
|
---|
| 1989 |
|
---|
| 1990 | if (tcp_fd->tf_flags & TFF_CONNECTING)
|
---|
| 1991 | {
|
---|
| 1992 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 1993 | assert(tcp_conn != NULL);
|
---|
| 1994 |
|
---|
| 1995 | assert (tcp_conn->tc_connInprogress);
|
---|
| 1996 | tcp_conn->tc_connInprogress= 0;
|
---|
| 1997 | tcp_conn->tc_fd= NULL;
|
---|
| 1998 | tcp_fd->tf_conn= NULL;
|
---|
| 1999 | tcp_close_connection(tcp_conn, ENOCONN);
|
---|
| 2000 |
|
---|
| 2001 | tcp_fd->tf_flags &= ~TFF_CONNECTING;
|
---|
| 2002 | }
|
---|
| 2003 |
|
---|
| 2004 | tcp_fd->tf_flags &= ~TFF_INUSE;
|
---|
| 2005 | if (!tcp_fd->tf_conn)
|
---|
| 2006 | return;
|
---|
| 2007 |
|
---|
| 2008 |
|
---|
| 2009 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 2010 | assert(tcp_conn->tc_fd == tcp_fd);
|
---|
| 2011 | tcp_conn->tc_fd= NULL;
|
---|
| 2012 |
|
---|
| 2013 | assert (!tcp_conn->tc_connInprogress);
|
---|
| 2014 |
|
---|
| 2015 | tcp_shutdown (tcp_conn);
|
---|
| 2016 | if (tcp_conn->tc_state == TCS_ESTABLISHED)
|
---|
| 2017 | {
|
---|
| 2018 | tcp_conn->tc_state= TCS_CLOSING;
|
---|
| 2019 | }
|
---|
| 2020 |
|
---|
| 2021 | /* Set the retransmission timeout a bit smaller. */
|
---|
| 2022 | tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_CLOSING;
|
---|
| 2023 |
|
---|
| 2024 | /* If all data has been acknowledged, close the connection. */
|
---|
| 2025 | if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
|
---|
| 2026 | tcp_close_connection(tcp_conn, ENOTCONN);
|
---|
| 2027 | }
|
---|
| 2028 |
|
---|
| 2029 | PUBLIC int tcp_cancel(fd, which_operation)
|
---|
| 2030 | int fd;
|
---|
| 2031 | int which_operation;
|
---|
| 2032 | {
|
---|
| 2033 | tcp_fd_t *tcp_fd;
|
---|
| 2034 | tcp_conn_t *tcp_conn;
|
---|
| 2035 |
|
---|
| 2036 | tcp_fd= &tcp_fd_table[fd];
|
---|
| 2037 |
|
---|
| 2038 | assert (tcp_fd->tf_flags & TFF_INUSE);
|
---|
| 2039 |
|
---|
| 2040 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 2041 |
|
---|
| 2042 | switch (which_operation)
|
---|
| 2043 | {
|
---|
| 2044 | case SR_CANCEL_WRITE:
|
---|
| 2045 | assert (tcp_fd->tf_flags & TFF_WRITE_IP);
|
---|
| 2046 | tcp_fd->tf_flags &= ~TFF_WRITE_IP;
|
---|
| 2047 |
|
---|
| 2048 | if (tcp_fd->tf_write_offset)
|
---|
| 2049 | reply_thr_get (tcp_fd, tcp_fd->tf_write_offset, FALSE);
|
---|
| 2050 | else
|
---|
| 2051 | reply_thr_get (tcp_fd, EINTR, FALSE);
|
---|
| 2052 | break;
|
---|
| 2053 | case SR_CANCEL_READ:
|
---|
| 2054 | assert (tcp_fd->tf_flags & TFF_READ_IP);
|
---|
| 2055 | tcp_fd->tf_flags &= ~TFF_READ_IP;
|
---|
| 2056 | if (tcp_fd->tf_read_offset)
|
---|
| 2057 | reply_thr_put (tcp_fd, tcp_fd->tf_read_offset, FALSE);
|
---|
| 2058 | else
|
---|
| 2059 | reply_thr_put (tcp_fd, EINTR, FALSE);
|
---|
| 2060 | break;
|
---|
| 2061 | case SR_CANCEL_IOCTL:
|
---|
| 2062 | assert (tcp_fd->tf_flags & TFF_IOCTL_IP);
|
---|
| 2063 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 2064 |
|
---|
| 2065 | if (tcp_fd->tf_flags & TFF_IOC_INIT_SP)
|
---|
| 2066 | {
|
---|
| 2067 | tcp_fd->tf_flags &= ~TFF_IOC_INIT_SP;
|
---|
| 2068 | reply_thr_put (tcp_fd, EINTR, TRUE);
|
---|
| 2069 | break;
|
---|
| 2070 | }
|
---|
| 2071 |
|
---|
| 2072 | switch (tcp_fd->tf_ioreq)
|
---|
| 2073 | {
|
---|
| 2074 | case NWIOGTCPCONF:
|
---|
| 2075 | reply_thr_put (tcp_fd, EINTR, TRUE);
|
---|
| 2076 | break;
|
---|
| 2077 | case NWIOSTCPCONF:
|
---|
| 2078 | case NWIOTCPSHUTDOWN:
|
---|
| 2079 | reply_thr_get (tcp_fd, EINTR, TRUE);
|
---|
| 2080 | break;
|
---|
| 2081 | case NWIOTCPCONN:
|
---|
| 2082 | case NWIOTCPLISTEN:
|
---|
| 2083 | assert (tcp_conn->tc_connInprogress);
|
---|
| 2084 | tcp_conn->tc_connInprogress= 0;
|
---|
| 2085 | tcp_conn->tc_fd= NULL;
|
---|
| 2086 | tcp_fd->tf_conn= NULL;
|
---|
| 2087 | tcp_close_connection(tcp_conn, ENOCONN);
|
---|
| 2088 | reply_thr_get (tcp_fd, EINTR, TRUE);
|
---|
| 2089 | break;
|
---|
| 2090 | default:
|
---|
| 2091 | ip_warning(( "unknown ioctl inprogress: 0x%x",
|
---|
| 2092 | tcp_fd->tf_ioreq ));
|
---|
| 2093 | reply_thr_get (tcp_fd, EINTR, TRUE);
|
---|
| 2094 | break;
|
---|
| 2095 | }
|
---|
| 2096 | break;
|
---|
| 2097 | default:
|
---|
| 2098 | ip_panic(( "unknown cancel request" ));
|
---|
| 2099 | break;
|
---|
| 2100 | }
|
---|
| 2101 | return NW_OK;
|
---|
| 2102 | }
|
---|
| 2103 |
|
---|
| 2104 | /*
|
---|
| 2105 | tcp_connect
|
---|
| 2106 | */
|
---|
| 2107 |
|
---|
| 2108 | PRIVATE int tcp_connect(tcp_fd)
|
---|
| 2109 | tcp_fd_t *tcp_fd;
|
---|
| 2110 | {
|
---|
| 2111 | tcp_conn_t *tcp_conn;
|
---|
| 2112 | nwio_tcpcl_t *tcpcl;
|
---|
| 2113 | long nwtcl_flags;
|
---|
| 2114 | int r, do_asynch;
|
---|
| 2115 | acc_t *data;
|
---|
| 2116 |
|
---|
| 2117 | if (!(tcp_fd->tf_flags & TFF_CONF_SET))
|
---|
| 2118 | {
|
---|
| 2119 | tcp_reply_ioctl(tcp_fd, EBADMODE);
|
---|
| 2120 | return NW_OK;
|
---|
| 2121 | }
|
---|
| 2122 | assert (!(tcp_fd->tf_flags & TFF_CONNECTED) &&
|
---|
| 2123 | !(tcp_fd->tf_flags & TFF_CONNECTING) &&
|
---|
| 2124 | !(tcp_fd->tf_flags & TFF_LISTENQ));
|
---|
| 2125 | if ((tcp_fd->tf_tcpconf.nwtc_flags & (NWTC_SET_RA|NWTC_SET_RP))
|
---|
| 2126 | != (NWTC_SET_RA|NWTC_SET_RP))
|
---|
| 2127 | {
|
---|
| 2128 | tcp_reply_ioctl(tcp_fd, EBADMODE);
|
---|
| 2129 | return NW_OK;
|
---|
| 2130 | }
|
---|
| 2131 |
|
---|
| 2132 | data= (*tcp_fd->tf_get_userdata) (tcp_fd->tf_srfd, 0,
|
---|
| 2133 | sizeof(*tcpcl), TRUE);
|
---|
| 2134 | if (!data)
|
---|
| 2135 | return EFAULT;
|
---|
| 2136 |
|
---|
| 2137 | data= bf_packIffLess(data, sizeof(*tcpcl));
|
---|
| 2138 | assert (data->acc_length == sizeof(*tcpcl));
|
---|
| 2139 | tcpcl= (nwio_tcpcl_t *)ptr2acc_data(data);
|
---|
| 2140 |
|
---|
| 2141 | nwtcl_flags= tcpcl->nwtcl_flags;
|
---|
| 2142 | bf_afree(data); data= NULL; tcpcl= NULL;
|
---|
| 2143 |
|
---|
| 2144 | if (nwtcl_flags == TCF_ASYNCH)
|
---|
| 2145 | do_asynch= 1;
|
---|
| 2146 | else if (nwtcl_flags == TCF_DEFAULT)
|
---|
| 2147 | do_asynch= 0;
|
---|
| 2148 | else
|
---|
| 2149 | {
|
---|
| 2150 | tcp_reply_ioctl(tcp_fd, EINVAL);
|
---|
| 2151 | return NW_OK;
|
---|
| 2152 | }
|
---|
| 2153 |
|
---|
| 2154 | assert(!tcp_fd->tf_conn);
|
---|
| 2155 | tcp_conn= find_conn_entry(tcp_fd->tf_tcpconf.nwtc_locport,
|
---|
| 2156 | tcp_fd->tf_port->tp_ipaddr,
|
---|
| 2157 | tcp_fd->tf_tcpconf.nwtc_remport,
|
---|
| 2158 | tcp_fd->tf_tcpconf.nwtc_remaddr);
|
---|
| 2159 | if (tcp_conn)
|
---|
| 2160 | {
|
---|
| 2161 | if (tcp_conn->tc_fd)
|
---|
| 2162 | {
|
---|
| 2163 | tcp_reply_ioctl(tcp_fd, EADDRINUSE);
|
---|
| 2164 | return NW_OK;
|
---|
| 2165 | }
|
---|
| 2166 | }
|
---|
| 2167 | else
|
---|
| 2168 | {
|
---|
| 2169 | tcp_conn= find_empty_conn();
|
---|
| 2170 | if (!tcp_conn)
|
---|
| 2171 | {
|
---|
| 2172 | tcp_reply_ioctl(tcp_fd, EAGAIN);
|
---|
| 2173 | return NW_OK;
|
---|
| 2174 | }
|
---|
| 2175 | }
|
---|
| 2176 | tcp_fd->tf_conn= tcp_conn;
|
---|
| 2177 |
|
---|
| 2178 | r= tcp_su4connect(tcp_fd);
|
---|
| 2179 | if (r == NW_SUSPEND && do_asynch)
|
---|
| 2180 | {
|
---|
| 2181 | tcp_fd->tf_flags |= TFF_CONNECTING;
|
---|
| 2182 | tcp_reply_ioctl(tcp_fd, EINPROGRESS);
|
---|
| 2183 | r= NW_OK;
|
---|
| 2184 | }
|
---|
| 2185 | return r;
|
---|
| 2186 | }
|
---|
| 2187 |
|
---|
| 2188 | /*
|
---|
| 2189 | tcp_su4connect
|
---|
| 2190 | */
|
---|
| 2191 |
|
---|
| 2192 | PRIVATE int tcp_su4connect(tcp_fd)
|
---|
| 2193 | tcp_fd_t *tcp_fd;
|
---|
| 2194 | {
|
---|
| 2195 | tcp_conn_t *tcp_conn;
|
---|
| 2196 |
|
---|
| 2197 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 2198 |
|
---|
| 2199 | tcp_conn->tc_locport= tcp_fd->tf_tcpconf.nwtc_locport;
|
---|
| 2200 | tcp_conn->tc_locaddr= tcp_fd->tf_port->tp_ipaddr;
|
---|
| 2201 |
|
---|
| 2202 | assert (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP);
|
---|
| 2203 | assert (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA);
|
---|
| 2204 | tcp_conn->tc_remport= tcp_fd->tf_tcpconf.nwtc_remport;
|
---|
| 2205 | tcp_conn->tc_remaddr= tcp_fd->tf_tcpconf.nwtc_remaddr;
|
---|
| 2206 |
|
---|
| 2207 | tcp_setup_conn(tcp_fd->tf_port, tcp_conn);
|
---|
| 2208 |
|
---|
| 2209 | tcp_conn->tc_fd= tcp_fd;
|
---|
| 2210 | tcp_conn->tc_connInprogress= 1;
|
---|
| 2211 | tcp_conn->tc_orglisten= FALSE;
|
---|
| 2212 | tcp_conn->tc_state= TCS_SYN_SENT;
|
---|
| 2213 | tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_CONNECT;
|
---|
| 2214 |
|
---|
| 2215 | /* Start the timer (if necessary) */
|
---|
| 2216 | tcp_set_send_timer(tcp_conn);
|
---|
| 2217 |
|
---|
| 2218 | tcp_conn_write(tcp_conn, 0);
|
---|
| 2219 |
|
---|
| 2220 | if (tcp_conn->tc_connInprogress)
|
---|
| 2221 | return NW_SUSPEND;
|
---|
| 2222 | else
|
---|
| 2223 | return NW_OK;
|
---|
| 2224 | }
|
---|
| 2225 |
|
---|
| 2226 |
|
---|
| 2227 | /*
|
---|
| 2228 | tcp_listen
|
---|
| 2229 | */
|
---|
| 2230 |
|
---|
| 2231 | PRIVATE int tcp_listen(tcp_fd, do_listenq)
|
---|
| 2232 | tcp_fd_t *tcp_fd;
|
---|
| 2233 | int do_listenq;
|
---|
| 2234 | {
|
---|
| 2235 | tcp_conn_t *tcp_conn;
|
---|
| 2236 |
|
---|
| 2237 | if (!(tcp_fd->tf_flags & TFF_CONF_SET))
|
---|
| 2238 | {
|
---|
| 2239 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 2240 | reply_thr_get(tcp_fd, EBADMODE, TRUE);
|
---|
| 2241 | return NW_OK;
|
---|
| 2242 | }
|
---|
| 2243 | assert (!(tcp_fd->tf_flags & TFF_CONNECTED) &&
|
---|
| 2244 | !(tcp_fd->tf_flags & TFF_CONNECTING) &&
|
---|
| 2245 | !(tcp_fd->tf_flags & TFF_LISTENQ));
|
---|
| 2246 | tcp_conn= tcp_fd->tf_conn;
|
---|
| 2247 | assert(!tcp_conn);
|
---|
| 2248 |
|
---|
| 2249 | if ((tcp_fd->tf_tcpconf.nwtc_flags & (NWTC_SET_RA|NWTC_SET_RP))
|
---|
| 2250 | == (NWTC_SET_RA|NWTC_SET_RP))
|
---|
| 2251 | {
|
---|
| 2252 | tcp_conn= find_conn_entry(
|
---|
| 2253 | tcp_fd->tf_tcpconf.nwtc_locport,
|
---|
| 2254 | tcp_fd->tf_port->tp_ipaddr,
|
---|
| 2255 | tcp_fd->tf_tcpconf.nwtc_remport,
|
---|
| 2256 | tcp_fd->tf_tcpconf.nwtc_remaddr);
|
---|
| 2257 | if (tcp_conn)
|
---|
| 2258 | {
|
---|
| 2259 | if (tcp_conn->tc_fd)
|
---|
| 2260 | {
|
---|
| 2261 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 2262 | reply_thr_get (tcp_fd, EADDRINUSE, TRUE);
|
---|
| 2263 | return NW_OK;
|
---|
| 2264 | }
|
---|
| 2265 | tcp_fd->tf_conn= tcp_conn;
|
---|
| 2266 | return tcp_su4listen(tcp_fd, tcp_conn, do_listenq);
|
---|
| 2267 | }
|
---|
| 2268 | }
|
---|
| 2269 | tcp_conn= find_empty_conn();
|
---|
| 2270 | if (!tcp_conn)
|
---|
| 2271 | {
|
---|
| 2272 | tcp_fd->tf_flags &= ~TFF_IOCTL_IP;
|
---|
| 2273 | reply_thr_get (tcp_fd, EAGAIN, TRUE);
|
---|
| 2274 | return NW_OK;
|
---|
| 2275 | }
|
---|
| 2276 | tcp_fd->tf_conn= tcp_conn;
|
---|
| 2277 | return tcp_su4listen(tcp_fd, tcp_conn, do_listenq);
|
---|
| 2278 | }
|
---|
| 2279 |
|
---|
| 2280 | /*
|
---|
| 2281 | tcp_acceptto
|
---|
| 2282 | */
|
---|
| 2283 |
|
---|
| 2284 | PRIVATE int tcp_acceptto(tcp_fd)
|
---|
| 2285 | tcp_fd_t *tcp_fd;
|
---|
| 2286 | {
|
---|
| 2287 | int i, dst_nr;
|
---|
| 2288 | tcp_fd_t *dst_fd;
|
---|
| 2289 | tcp_conn_t *tcp_conn;
|
---|
| 2290 | tcp_cookie_t *cookiep;
|
---|
| 2291 | acc_t *data;
|
---|
| 2292 | tcp_cookie_t cookie;
|
---|
| 2293 |
|
---|
| 2294 | if (!(tcp_fd->tf_flags & TFF_LISTENQ))
|
---|
| 2295 | {
|
---|
| 2296 | tcp_reply_ioctl(tcp_fd, EINVAL);
|
---|
| 2297 | return NW_OK;
|
---|
| 2298 | }
|
---|
| 2299 | for (i= 0; i<TFL_LISTEN_MAX; i++)
|
---|
| 2300 | {
|
---|
| 2301 | tcp_conn= tcp_fd->tf_listenq[i];
|
---|
| 2302 | if (tcp_conn && !tcp_conn->tc_connInprogress)
|
---|
| 2303 | break;
|
---|
| 2304 | }
|
---|
| 2305 | if (i >= TFL_LISTEN_MAX)
|
---|
| 2306 | {
|
---|
| 2307 | /* Nothing, suspend caller */
|
---|
| 2308 | return NW_SUSPEND;
|
---|
| 2309 | }
|
---|
| 2310 |
|
---|
| 2311 | data= (*tcp_fd->tf_get_userdata) (tcp_fd->tf_srfd, 0,
|
---|
| 2312 | sizeof(*cookiep), TRUE);
|
---|
| 2313 | if (!data)
|
---|
| 2314 | return EFAULT;
|
---|
| 2315 |
|
---|
| 2316 | data= bf_packIffLess(data, sizeof(*cookiep));
|
---|
| 2317 | cookiep= (tcp_cookie_t *)ptr2acc_data(data);
|
---|
| 2318 | cookie= *cookiep;
|
---|
| 2319 |
|
---|
| 2320 | bf_afree(data); data= NULL;
|
---|
| 2321 |
|
---|
| 2322 | dst_nr= cookie.tc_ref;
|
---|
| 2323 | if (dst_nr < 0 || dst_nr >= TCP_FD_NR)
|
---|
| 2324 | {
|
---|
| 2325 | printf("tcp_acceptto: bad fd %d\n", dst_nr);
|
---|
| 2326 | tcp_reply_ioctl(tcp_fd, EINVAL);
|
---|
| 2327 | return NW_OK;
|
---|
| 2328 | }
|
---|
| 2329 | dst_fd= &tcp_fd_table[dst_nr];
|
---|
| 2330 | if (!(dst_fd->tf_flags & TFF_INUSE) ||
|
---|
| 2331 | (dst_fd->tf_flags & (TFF_READ_IP|TFF_WRITE_IP|TFF_IOCTL_IP)) ||
|
---|
| 2332 | dst_fd->tf_conn != NULL ||
|
---|
| 2333 | !(dst_fd->tf_flags & TFF_COOKIE))
|
---|
| 2334 | {
|
---|
| 2335 | printf("tcp_acceptto: bad flags 0x%x or conn %p for fd %d\n",
|
---|
| 2336 | dst_fd->tf_flags, dst_fd->tf_conn, dst_nr);
|
---|
| 2337 | tcp_reply_ioctl(tcp_fd, EINVAL);
|
---|
| 2338 | return NW_OK;
|
---|
| 2339 | }
|
---|
| 2340 | if (memcmp(&cookie, &dst_fd->tf_cookie, sizeof(cookie)) != 0)
|
---|
| 2341 | {
|
---|
| 2342 | printf("tcp_acceptto: bad cookie\n");
|
---|
| 2343 | return NW_OK;
|
---|
| 2344 | }
|
---|
| 2345 |
|
---|
| 2346 | /* Move connection */
|
---|
| 2347 | tcp_fd->tf_listenq[i]= NULL;
|
---|
| 2348 | tcp_conn->tc_fd= dst_fd;
|
---|
| 2349 | dst_fd->tf_conn= tcp_conn;
|
---|
| 2350 | dst_fd->tf_flags |= TFF_CONNECTED;
|
---|
| 2351 |
|
---|
| 2352 | tcp_reply_ioctl(tcp_fd, NW_OK);
|
---|
| 2353 | return NW_OK;
|
---|
| 2354 | }
|
---|
| 2355 |
|
---|
| 2356 |
|
---|
| 2357 | PRIVATE void tcp_buffree (priority)
|
---|
| 2358 | int priority;
|
---|
| 2359 | {
|
---|
| 2360 | int i;
|
---|
| 2361 | tcp_conn_t *tcp_conn;
|
---|
| 2362 |
|
---|
| 2363 | if (priority == TCP_PRI_FRAG2SEND)
|
---|
| 2364 | {
|
---|
| 2365 | for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
|
---|
| 2366 | tcp_conn++)
|
---|
| 2367 | {
|
---|
| 2368 | if (!(tcp_conn->tc_flags & TCF_INUSE))
|
---|
| 2369 | continue;
|
---|
| 2370 | if (!tcp_conn->tc_frag2send)
|
---|
| 2371 | continue;
|
---|
| 2372 | if (tcp_conn->tc_busy)
|
---|
| 2373 | continue;
|
---|
| 2374 | bf_afree(tcp_conn->tc_frag2send);
|
---|
| 2375 | tcp_conn->tc_frag2send= 0;
|
---|
| 2376 | }
|
---|
| 2377 | }
|
---|
| 2378 |
|
---|
| 2379 | if (priority == TCP_PRI_CONN_EXTRA)
|
---|
| 2380 | {
|
---|
| 2381 | for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
|
---|
| 2382 | tcp_conn++)
|
---|
| 2383 | {
|
---|
| 2384 | if (!(tcp_conn->tc_flags & TCF_INUSE))
|
---|
| 2385 | continue;
|
---|
| 2386 | if (tcp_conn->tc_busy)
|
---|
| 2387 | continue;
|
---|
| 2388 | if (tcp_conn->tc_adv_data)
|
---|
| 2389 | {
|
---|
| 2390 | bf_afree(tcp_conn->tc_adv_data);
|
---|
| 2391 | tcp_conn->tc_adv_data= NULL;
|
---|
| 2392 | }
|
---|
| 2393 | }
|
---|
| 2394 | }
|
---|
| 2395 |
|
---|
| 2396 | if (priority == TCP_PRI_CONNwoUSER)
|
---|
| 2397 | {
|
---|
| 2398 | for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
|
---|
| 2399 | tcp_conn++)
|
---|
| 2400 | {
|
---|
| 2401 | if (!(tcp_conn->tc_flags & TCF_INUSE))
|
---|
| 2402 | continue;
|
---|
| 2403 | if (tcp_conn->tc_busy)
|
---|
| 2404 | continue;
|
---|
| 2405 | if (tcp_conn->tc_fd)
|
---|
| 2406 | continue;
|
---|
| 2407 | if (tcp_conn->tc_state == TCS_CLOSED)
|
---|
| 2408 | continue;
|
---|
| 2409 | if (tcp_conn->tc_rcvd_data == NULL &&
|
---|
| 2410 | tcp_conn->tc_send_data == NULL)
|
---|
| 2411 | {
|
---|
| 2412 | continue;
|
---|
| 2413 | }
|
---|
| 2414 | tcp_close_connection (tcp_conn, EOUTOFBUFS);
|
---|
| 2415 | }
|
---|
| 2416 | }
|
---|
| 2417 |
|
---|
| 2418 | if (priority == TCP_PRI_CONN_INUSE)
|
---|
| 2419 | {
|
---|
| 2420 | for (i=0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++,
|
---|
| 2421 | tcp_conn++)
|
---|
| 2422 | {
|
---|
| 2423 | if (!(tcp_conn->tc_flags & TCF_INUSE))
|
---|
| 2424 | continue;
|
---|
| 2425 | if (tcp_conn->tc_busy)
|
---|
| 2426 | continue;
|
---|
| 2427 | if (tcp_conn->tc_state == TCS_CLOSED)
|
---|
| 2428 | continue;
|
---|
| 2429 | if (tcp_conn->tc_rcvd_data == NULL &&
|
---|
| 2430 | tcp_conn->tc_send_data == NULL)
|
---|
| 2431 | {
|
---|
| 2432 | continue;
|
---|
| 2433 | }
|
---|
| 2434 | tcp_close_connection (tcp_conn, EOUTOFBUFS);
|
---|
| 2435 | }
|
---|
| 2436 | }
|
---|
| 2437 | }
|
---|
| 2438 |
|
---|
| 2439 | #ifdef BUF_CONSISTENCY_CHECK
|
---|
| 2440 | PRIVATE void tcp_bufcheck()
|
---|
| 2441 | {
|
---|
| 2442 | int i;
|
---|
| 2443 | tcp_conn_t *tcp_conn;
|
---|
| 2444 | tcp_port_t *tcp_port;
|
---|
| 2445 |
|
---|
| 2446 | for (i= 0, tcp_port= tcp_port_table; i<tcp_conf_nr; i++, tcp_port++)
|
---|
| 2447 | {
|
---|
| 2448 | if (tcp_port->tp_pack)
|
---|
| 2449 | bf_check_acc(tcp_port->tp_pack);
|
---|
| 2450 | }
|
---|
| 2451 | for (i= 0, tcp_conn= tcp_conn_table; i<TCP_CONN_NR; i++, tcp_conn++)
|
---|
| 2452 | {
|
---|
| 2453 | assert(!tcp_conn->tc_busy);
|
---|
| 2454 | if (tcp_conn->tc_rcvd_data)
|
---|
| 2455 | bf_check_acc(tcp_conn->tc_rcvd_data);
|
---|
| 2456 | if (tcp_conn->tc_adv_data)
|
---|
| 2457 | bf_check_acc(tcp_conn->tc_adv_data);
|
---|
| 2458 | if (tcp_conn->tc_send_data)
|
---|
| 2459 | bf_check_acc(tcp_conn->tc_send_data);
|
---|
| 2460 | if (tcp_conn->tc_remipopt)
|
---|
| 2461 | bf_check_acc(tcp_conn->tc_remipopt);
|
---|
| 2462 | if (tcp_conn->tc_tcpopt)
|
---|
| 2463 | bf_check_acc(tcp_conn->tc_tcpopt);
|
---|
| 2464 | if (tcp_conn->tc_frag2send)
|
---|
| 2465 | bf_check_acc(tcp_conn->tc_frag2send);
|
---|
| 2466 | }
|
---|
| 2467 | }
|
---|
| 2468 | #endif
|
---|
| 2469 |
|
---|
| 2470 | PUBLIC void tcp_notreach(tcp_conn)
|
---|
| 2471 | tcp_conn_t *tcp_conn;
|
---|
| 2472 | {
|
---|
| 2473 | int new_ttl;
|
---|
| 2474 |
|
---|
| 2475 | new_ttl= tcp_conn->tc_ttl;
|
---|
| 2476 | if (new_ttl == IP_MAX_TTL)
|
---|
| 2477 | {
|
---|
| 2478 | if (tcp_conn->tc_state == TCS_SYN_SENT)
|
---|
| 2479 | tcp_close_connection(tcp_conn, EDSTNOTRCH);
|
---|
| 2480 | return;
|
---|
| 2481 | }
|
---|
| 2482 | else if (new_ttl < TCP_DEF_TTL_NEXT)
|
---|
| 2483 | new_ttl= TCP_DEF_TTL_NEXT;
|
---|
| 2484 | else
|
---|
| 2485 | {
|
---|
| 2486 | new_ttl *= 2;
|
---|
| 2487 | if (new_ttl> IP_MAX_TTL)
|
---|
| 2488 | new_ttl= IP_MAX_TTL;
|
---|
| 2489 | }
|
---|
| 2490 | tcp_conn->tc_ttl= new_ttl;
|
---|
| 2491 | tcp_conn->tc_stt= 0;
|
---|
| 2492 | tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
|
---|
| 2493 | tcp_conn_write(tcp_conn, 1);
|
---|
| 2494 | }
|
---|
| 2495 |
|
---|
| 2496 | FORWARD u32_t mtu_table[]=
|
---|
| 2497 | { /* From RFC-1191 */
|
---|
| 2498 | /* Plateau MTU Comments Reference */
|
---|
| 2499 | /* ------ --- -------- --------- */
|
---|
| 2500 | /* 65535 Official maximum MTU RFC 791 */
|
---|
| 2501 | /* 65535 Hyperchannel RFC 1044 */
|
---|
| 2502 | 65535,
|
---|
| 2503 | 32000, /* Just in case */
|
---|
| 2504 | /* 17914 16Mb IBM Token Ring ref. [6] */
|
---|
| 2505 | 17914,
|
---|
| 2506 | /* 8166 IEEE 802.4 RFC 1042 */
|
---|
| 2507 | 8166,
|
---|
| 2508 | /* 4464 IEEE 802.5 (4Mb max) RFC 1042 */
|
---|
| 2509 | /* 4352 FDDI (Revised) RFC 1188 */
|
---|
| 2510 | 4352, /* (1%) */
|
---|
| 2511 | /* 2048 Wideband Network RFC 907 */
|
---|
| 2512 | /* 2002 IEEE 802.5 (4Mb recommended) RFC 1042 */
|
---|
| 2513 | 2002, /* (2%) */
|
---|
| 2514 | /* 1536 Exp. Ethernet Nets RFC 895 */
|
---|
| 2515 | /* 1500 Ethernet Networks RFC 894 */
|
---|
| 2516 | /* 1500 Point-to-Point (default) RFC 1134 */
|
---|
| 2517 | /* 1492 IEEE 802.3 RFC 1042 */
|
---|
| 2518 | 1492, /* (3%) */
|
---|
| 2519 | /* 1006 SLIP RFC 1055 */
|
---|
| 2520 | /* 1006 ARPANET BBN 1822 */
|
---|
| 2521 | 1006,
|
---|
| 2522 | /* 576 X.25 Networks RFC 877 */
|
---|
| 2523 | /* 544 DEC IP Portal ref. [10] */
|
---|
| 2524 | /* 512 NETBIOS RFC 1088 */
|
---|
| 2525 | /* 508 IEEE 802/Source-Rt Bridge RFC 1042 */
|
---|
| 2526 | /* 508 ARCNET RFC 1051 */
|
---|
| 2527 | 508, /* (13%) */
|
---|
| 2528 | /* 296 Point-to-Point (low delay) RFC 1144 */
|
---|
| 2529 | 296,
|
---|
| 2530 | 68, /* Official minimum MTU RFC 791 */
|
---|
| 2531 | 0, /* End of list */
|
---|
| 2532 | };
|
---|
| 2533 |
|
---|
| 2534 | PUBLIC void tcp_mtu_exceeded(tcp_conn)
|
---|
| 2535 | tcp_conn_t *tcp_conn;
|
---|
| 2536 | {
|
---|
| 2537 | u16_t mtu;
|
---|
| 2538 | int i;
|
---|
| 2539 | clock_t curr_time;
|
---|
| 2540 |
|
---|
| 2541 | if (!(tcp_conn->tc_flags & TCF_PMTU))
|
---|
| 2542 | {
|
---|
| 2543 | /* Strange, got MTU exceeded but DF is not set. Ignore
|
---|
| 2544 | * the error. If the problem persists, the connection will
|
---|
| 2545 | * time-out.
|
---|
| 2546 | */
|
---|
| 2547 | return;
|
---|
| 2548 | }
|
---|
| 2549 | curr_time= get_time();
|
---|
| 2550 |
|
---|
| 2551 | /* We get here in cases. Either were are trying to find an MTU
|
---|
| 2552 | * that works at all, or we are trying see how far we can increase
|
---|
| 2553 | * the current MTU. If the last change to the MTU was a long time
|
---|
| 2554 | * ago, we assume the second case.
|
---|
| 2555 | */
|
---|
| 2556 | if (curr_time >= tcp_conn->tc_mtutim + TCP_PMTU_INCR_IV)
|
---|
| 2557 | {
|
---|
| 2558 | mtu= tcp_conn->tc_mtu;
|
---|
| 2559 | mtu -= mtu/TCP_PMTU_INCR_FRAC;
|
---|
| 2560 | tcp_conn->tc_mtu= mtu;
|
---|
| 2561 | tcp_conn->tc_mtutim= curr_time;
|
---|
| 2562 | DBLOCK(1, printf(
|
---|
| 2563 | "tcp_mtu_exceeded: new (lowered) mtu %d for conn %d\n",
|
---|
| 2564 | mtu, tcp_conn-tcp_conn_table));
|
---|
| 2565 | tcp_conn->tc_stt= 0;
|
---|
| 2566 | tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
|
---|
| 2567 | tcp_conn_write(tcp_conn, 1);
|
---|
| 2568 | return;
|
---|
| 2569 | }
|
---|
| 2570 |
|
---|
| 2571 | tcp_conn->tc_mtutim= curr_time;
|
---|
| 2572 | mtu= tcp_conn->tc_mtu;
|
---|
| 2573 | for (i= 0; mtu_table[i] >= mtu; i++)
|
---|
| 2574 | ; /* Nothing to do */
|
---|
| 2575 | mtu= mtu_table[i];
|
---|
| 2576 | if (mtu >= TCP_MIN_PATH_MTU)
|
---|
| 2577 | {
|
---|
| 2578 | tcp_conn->tc_mtu= mtu;
|
---|
| 2579 | }
|
---|
| 2580 | else
|
---|
| 2581 | {
|
---|
| 2582 | /* Small MTUs can be used for denial-of-service attacks.
|
---|
| 2583 | * Switch-off PMTU if the MTU becomes too small.
|
---|
| 2584 | */
|
---|
| 2585 | tcp_conn->tc_flags &= ~TCF_PMTU;
|
---|
| 2586 | tcp_conn->tc_mtu= TCP_MIN_PATH_MTU;
|
---|
| 2587 | DBLOCK(1, printf(
|
---|
| 2588 | "tcp_mtu_exceeded: clearing TCF_PMTU for conn %d\n",
|
---|
| 2589 | tcp_conn-tcp_conn_table););
|
---|
| 2590 |
|
---|
| 2591 | }
|
---|
| 2592 | DBLOCK(1, printf("tcp_mtu_exceeded: new mtu %d for conn %d\n",
|
---|
| 2593 | mtu, tcp_conn-tcp_conn_table););
|
---|
| 2594 | tcp_conn->tc_stt= 0;
|
---|
| 2595 | tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
|
---|
| 2596 | tcp_conn_write(tcp_conn, 1);
|
---|
| 2597 | }
|
---|
| 2598 |
|
---|
| 2599 | PUBLIC void tcp_mtu_incr(tcp_conn)
|
---|
| 2600 | tcp_conn_t *tcp_conn;
|
---|
| 2601 | {
|
---|
| 2602 | clock_t curr_time;
|
---|
| 2603 | u32_t mtu;
|
---|
| 2604 |
|
---|
| 2605 | assert(tcp_conn->tc_mtu < tcp_conn->tc_max_mtu);
|
---|
| 2606 | if (!(tcp_conn->tc_flags & TCF_PMTU))
|
---|
| 2607 | {
|
---|
| 2608 | /* Use a much longer time-out for retrying PMTU discovery
|
---|
| 2609 | * after is has been disabled. Note that PMTU discovery
|
---|
| 2610 | * can be disabled during a short loss of connectivity.
|
---|
| 2611 | */
|
---|
| 2612 | curr_time= get_time();
|
---|
| 2613 | if (curr_time > tcp_conn->tc_mtutim+TCP_PMTU_EN_IV)
|
---|
| 2614 | {
|
---|
| 2615 | tcp_conn->tc_flags |= TCF_PMTU;
|
---|
| 2616 | DBLOCK(1, printf(
|
---|
| 2617 | "tcp_mtu_incr: setting TCF_PMTU for conn %d\n",
|
---|
| 2618 | tcp_conn-tcp_conn_table););
|
---|
| 2619 | }
|
---|
| 2620 | return;
|
---|
| 2621 | }
|
---|
| 2622 |
|
---|
| 2623 | mtu= tcp_conn->tc_mtu;
|
---|
| 2624 | mtu += mtu/TCP_PMTU_INCR_FRAC;
|
---|
| 2625 | if (mtu > tcp_conn->tc_max_mtu)
|
---|
| 2626 | mtu= tcp_conn->tc_max_mtu;
|
---|
| 2627 | tcp_conn->tc_mtu= mtu;
|
---|
| 2628 | DBLOCK(0x1, printf("tcp_mtu_incr: new mtu %ld for conn %d\n",
|
---|
| 2629 | mtu, tcp_conn-tcp_conn_table););
|
---|
| 2630 | }
|
---|
| 2631 |
|
---|
| 2632 | /*
|
---|
| 2633 | tcp_setup_conn
|
---|
| 2634 | */
|
---|
| 2635 |
|
---|
| 2636 | PRIVATE void tcp_setup_conn(tcp_port, tcp_conn)
|
---|
| 2637 | tcp_port_t *tcp_port;
|
---|
| 2638 | tcp_conn_t *tcp_conn;
|
---|
| 2639 | {
|
---|
| 2640 | u16_t mss;
|
---|
| 2641 |
|
---|
| 2642 | assert(!tcp_conn->tc_connInprogress);
|
---|
| 2643 | tcp_conn->tc_port= tcp_port;
|
---|
| 2644 | if (tcp_conn->tc_flags & TCF_INUSE)
|
---|
| 2645 | {
|
---|
| 2646 | assert (tcp_conn->tc_state == TCS_CLOSED);
|
---|
| 2647 | assert (!tcp_conn->tc_send_data);
|
---|
| 2648 | if (tcp_conn->tc_senddis < get_time())
|
---|
| 2649 | tcp_conn->tc_ISS= 0;
|
---|
| 2650 | }
|
---|
| 2651 | else
|
---|
| 2652 | {
|
---|
| 2653 | assert(!tcp_conn->tc_busy);
|
---|
| 2654 | tcp_conn->tc_senddis= 0;
|
---|
| 2655 | tcp_conn->tc_ISS= 0;
|
---|
| 2656 | tcp_conn->tc_tos= TCP_DEF_TOS;
|
---|
| 2657 | tcp_conn->tc_ttl= TCP_DEF_TTL;
|
---|
| 2658 | tcp_conn->tc_rcv_wnd= TCP_MAX_RCV_WND_SIZE;
|
---|
| 2659 | tcp_conn->tc_fd= NULL;
|
---|
| 2660 | }
|
---|
| 2661 | if (!tcp_conn->tc_ISS)
|
---|
| 2662 | {
|
---|
| 2663 | tcp_conn->tc_ISS= tcp_rand32();
|
---|
| 2664 | }
|
---|
| 2665 | tcp_conn->tc_SND_UNA= tcp_conn->tc_ISS;
|
---|
| 2666 | tcp_conn->tc_SND_TRM= tcp_conn->tc_ISS;
|
---|
| 2667 | tcp_conn->tc_SND_NXT= tcp_conn->tc_ISS+1;
|
---|
| 2668 | tcp_conn->tc_SND_UP= tcp_conn->tc_ISS;
|
---|
| 2669 | tcp_conn->tc_SND_PSH= tcp_conn->tc_ISS+1;
|
---|
| 2670 | tcp_conn->tc_IRS= 0;
|
---|
| 2671 | tcp_conn->tc_RCV_LO= tcp_conn->tc_IRS;
|
---|
| 2672 | tcp_conn->tc_RCV_NXT= tcp_conn->tc_IRS;
|
---|
| 2673 | tcp_conn->tc_RCV_HI= tcp_conn->tc_IRS;
|
---|
| 2674 | tcp_conn->tc_RCV_UP= tcp_conn->tc_IRS;
|
---|
| 2675 |
|
---|
| 2676 | assert(tcp_conn->tc_rcvd_data == NULL);
|
---|
| 2677 | assert(tcp_conn->tc_adv_data == NULL);
|
---|
| 2678 | assert(tcp_conn->tc_send_data == NULL);
|
---|
| 2679 |
|
---|
| 2680 | tcp_conn->tc_ka_time= TCP_DEF_KEEPALIVE;
|
---|
| 2681 |
|
---|
| 2682 | tcp_conn->tc_remipopt= NULL;
|
---|
| 2683 | tcp_conn->tc_tcpopt= NULL;
|
---|
| 2684 |
|
---|
| 2685 | assert(tcp_conn->tc_frag2send == NULL);
|
---|
| 2686 |
|
---|
| 2687 | tcp_conn->tc_stt= 0;
|
---|
| 2688 | tcp_conn->tc_rt_dead= TCP_DEF_RT_DEAD;
|
---|
| 2689 | tcp_conn->tc_0wnd_to= 0;
|
---|
| 2690 | tcp_conn->tc_artt= TCP_DEF_RTT*TCP_RTT_SCALE;
|
---|
| 2691 | tcp_conn->tc_drtt= 0;
|
---|
| 2692 | tcp_conn->tc_rtt= TCP_DEF_RTT;
|
---|
| 2693 | tcp_conn->tc_max_mtu= tcp_conn->tc_port->tp_mtu;
|
---|
| 2694 | tcp_conn->tc_mtu= tcp_conn->tc_max_mtu;
|
---|
| 2695 | tcp_conn->tc_mtutim= 0;
|
---|
| 2696 | tcp_conn->tc_error= NW_OK;
|
---|
| 2697 | mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
|
---|
| 2698 | tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA + 2*mss;
|
---|
| 2699 | tcp_conn->tc_snd_cthresh= TCP_MAX_SND_WND_SIZE;
|
---|
| 2700 | tcp_conn->tc_snd_cinc=
|
---|
| 2701 | (long)TCP_DEF_MSS*TCP_DEF_MSS/TCP_MAX_SND_WND_SIZE+1;
|
---|
| 2702 | tcp_conn->tc_snd_wnd= TCP_MAX_SND_WND_SIZE;
|
---|
| 2703 | tcp_conn->tc_rt_time= 0;
|
---|
| 2704 | tcp_conn->tc_rt_seq= 0;
|
---|
| 2705 | tcp_conn->tc_rt_threshold= tcp_conn->tc_ISS;
|
---|
| 2706 | tcp_conn->tc_flags= TCF_INUSE;
|
---|
| 2707 | tcp_conn->tc_flags |= TCF_PMTU;
|
---|
| 2708 |
|
---|
| 2709 | clck_untimer(&tcp_conn->tc_transmit_timer);
|
---|
| 2710 | tcp_conn->tc_transmit_seq= 0;
|
---|
| 2711 | }
|
---|
| 2712 |
|
---|
| 2713 | PRIVATE u32_t tcp_rand32()
|
---|
| 2714 | {
|
---|
| 2715 | u8_t bits[RAND256_BUFSIZE];
|
---|
| 2716 |
|
---|
| 2717 | rand256(bits);
|
---|
| 2718 | return bits[0] | (bits[1] << 8) | (bits[2] << 16) | (bits[3] << 24);
|
---|
| 2719 | }
|
---|
| 2720 |
|
---|
| 2721 | /*
|
---|
| 2722 | * $PchId: tcp.c,v 1.34 2005/06/28 14:20:27 philip Exp $
|
---|
| 2723 | */
|
---|