source: trunk/minix/servers/inet/generic/tcp.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 61.0 KB
Line 
1/*
2tcp.c
3
4Copyright 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
21THIS_FILE
22
23#define NOT_IMPLEMENTED 0
24
25PUBLIC tcp_port_t *tcp_port_table;
26PUBLIC tcp_fd_t tcp_fd_table[TCP_FD_NR];
27PUBLIC tcp_conn_t tcp_conn_table[TCP_CONN_NR];
28PUBLIC sr_cancel_t tcp_cancel_f;
29
30FORWARD void tcp_main ARGS(( tcp_port_t *port ));
31FORWARD int tcp_select ARGS(( int fd, unsigned operations ));
32FORWARD acc_t *tcp_get_data ARGS(( int fd, size_t offset,
33 size_t count, int for_ioctl ));
34FORWARD int tcp_put_data ARGS(( int fd, size_t offset,
35 acc_t *data, int for_ioctl ));
36FORWARD void tcp_put_pkt ARGS(( int fd, acc_t *data, size_t datalen ));
37FORWARD void read_ip_packets ARGS(( tcp_port_t *port ));
38FORWARD int tcp_setconf ARGS(( tcp_fd_t *tcp_fd ));
39FORWARD int tcp_setopt ARGS(( tcp_fd_t *tcp_fd ));
40FORWARD int tcp_connect ARGS(( tcp_fd_t *tcp_fd ));
41FORWARD int tcp_listen ARGS(( tcp_fd_t *tcp_fd, int do_listenq ));
42FORWARD int tcp_acceptto ARGS(( tcp_fd_t *tcp_fd ));
43FORWARD tcpport_t find_unused_port ARGS(( int fd ));
44FORWARD int is_unused_port ARGS(( Tcpport_t port ));
45FORWARD int reply_thr_put ARGS(( tcp_fd_t *tcp_fd, int reply,
46 int for_ioctl ));
47FORWARD void reply_thr_get ARGS(( tcp_fd_t *tcp_fd, int reply,
48 int for_ioctl ));
49FORWARD tcp_conn_t *find_conn_entry ARGS(( Tcpport_t locport,
50 ipaddr_t locaddr, Tcpport_t remport, ipaddr_t readaddr ));
51FORWARD tcp_conn_t *find_empty_conn ARGS(( void ));
52FORWARD tcp_conn_t *find_best_conn ARGS(( ip_hdr_t *ip_hdr,
53 tcp_hdr_t *tcp_hdr ));
54FORWARD tcp_conn_t *new_conn_for_queue ARGS(( tcp_fd_t *tcp_fd ));
55FORWARD int maybe_listen ARGS(( ipaddr_t locaddr, Tcpport_t locport,
56 ipaddr_t remaddr, Tcpport_t remport ));
57FORWARD int tcp_su4connect ARGS(( tcp_fd_t *tcp_fd ));
58FORWARD void tcp_buffree ARGS(( int priority ));
59#ifdef BUF_CONSISTENCY_CHECK
60FORWARD void tcp_bufcheck ARGS(( void ));
61#endif
62FORWARD void tcp_setup_conn ARGS(( tcp_port_t *tcp_port,
63 tcp_conn_t *tcp_conn ));
64FORWARD u32_t tcp_rand32 ARGS(( void ));
65
66PUBLIC void tcp_prep()
67{
68 tcp_port_table= alloc(tcp_conf_nr * sizeof(tcp_port_table[0]));
69}
70
71PUBLIC 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
129PRIVATE void tcp_main(tcp_port)
130tcp_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
250PRIVATE int tcp_select(fd, operations)
251int fd;
252unsigned 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
346PRIVATE acc_t *tcp_get_data (port, offset, count, for_ioctl)
347int port;
348size_t offset;
349size_t count;
350int 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 }
373assert (!offset);
374assert (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
438PRIVATE int tcp_put_data (fd, offset, data, for_ioctl)
439int fd;
440size_t offset;
441acc_t *data;
442int 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);
470assert (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/*
512tcp_put_pkt
513*/
514
515PRIVATE void tcp_put_pkt(fd, data, datalen)
516int fd;
517acc_t *data;
518size_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
713PUBLIC int tcp_open (port, srfd, get_userdata, put_userdata, put_pkt,
714 select_res)
715int port;
716int srfd;
717get_userdata_t get_userdata;
718put_userdata_t put_userdata;
719put_pkt_t put_pkt;
720select_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/*
755tcp_ioctl
756*/
757PUBLIC int tcp_ioctl (fd, req)
758int fd;
759ioreq_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));
801assert (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/*
969tcp_setconf
970*/
971
972PRIVATE int tcp_setconf(tcp_fd)
973tcp_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));
991assert (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 {
1077assert (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 {
1103assert (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/*
1160tcp_setopt
1161*/
1162
1163PRIVATE int tcp_setopt(tcp_fd)
1164tcp_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));
1179assert (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
1279PRIVATE tcpport_t find_unused_port(fd)
1280int 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
1300PRIVATE int is_unused_port(port)
1301tcpport_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
1327PRIVATE int reply_thr_put(tcp_fd, reply, for_ioctl)
1328tcp_fd_t *tcp_fd;
1329int reply;
1330int 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
1338PRIVATE void reply_thr_get(tcp_fd, reply, for_ioctl)
1339tcp_fd_t *tcp_fd;
1340int reply;
1341int 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
1350PUBLIC int tcp_su4listen(tcp_fd, tcp_conn, do_listenq)
1351tcp_fd_t *tcp_fd;
1352tcp_conn_t *tcp_conn;
1353int 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/*
1382find_empty_conn
1383
1384This function returns a connection that is not inuse.
1385This includes connections that are never used, and connections without a
1386user that are not used for a while.
1387*/
1388
1389PRIVATE 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/*
1422find_conn_entry
1423
1424This function return a connection matching locport, locaddr, remport, remaddr.
1425If no such connection exists NULL is returned.
1426If a connection exists without mainuser it is closed.
1427*/
1428
1429PRIVATE tcp_conn_t *find_conn_entry(locport, locaddr, remport, remaddr)
1430tcpport_t locport;
1431ipaddr_t locaddr;
1432tcpport_t remport;
1433ipaddr_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
1464PRIVATE void read_ip_packets(tcp_port)
1465tcp_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/*
1484find_best_conn
1485*/
1486
1487PRIVATE tcp_conn_t *find_best_conn(ip_hdr, tcp_hdr)
1488ip_hdr_t *ip_hdr;
1489tcp_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/*
1653new_conn_for_queue
1654*/
1655PRIVATE tcp_conn_t *new_conn_for_queue(tcp_fd)
1656tcp_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/*
1680maybe_listen
1681*/
1682PRIVATE int maybe_listen(locaddr, locport, remaddr, remport)
1683ipaddr_t locaddr;
1684tcpport_t locport;
1685ipaddr_t remaddr;
1686tcpport_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
1730PUBLIC void tcp_reply_ioctl(tcp_fd, reply)
1731tcp_fd_t *tcp_fd;
1732int 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
1745PUBLIC void tcp_reply_write(tcp_fd, reply)
1746tcp_fd_t *tcp_fd;
1747size_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
1755PUBLIC void tcp_reply_read(tcp_fd, reply)
1756tcp_fd_t *tcp_fd;
1757size_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
1765PUBLIC int tcp_write(fd, count)
1766int fd;
1767size_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
1818PUBLIC int
1819tcp_read(fd, count)
1820int fd;
1821size_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/*
1852tcp_restart_connect
1853
1854reply the success or failure of a connect to the user.
1855*/
1856
1857
1858PUBLIC void tcp_restart_connect(tcp_conn)
1859tcp_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/*
1929tcp_close
1930*/
1931
1932PUBLIC void tcp_close(fd)
1933int 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
2029PUBLIC int tcp_cancel(fd, which_operation)
2030int fd;
2031int 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:
2062assert (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/*
2105tcp_connect
2106*/
2107
2108PRIVATE int tcp_connect(tcp_fd)
2109tcp_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/*
2189tcp_su4connect
2190*/
2191
2192PRIVATE int tcp_su4connect(tcp_fd)
2193tcp_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/*
2228tcp_listen
2229*/
2230
2231PRIVATE int tcp_listen(tcp_fd, do_listenq)
2232tcp_fd_t *tcp_fd;
2233int 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/*
2281tcp_acceptto
2282*/
2283
2284PRIVATE int tcp_acceptto(tcp_fd)
2285tcp_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
2357PRIVATE void tcp_buffree (priority)
2358int 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
2440PRIVATE 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
2470PUBLIC void tcp_notreach(tcp_conn)
2471tcp_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
2496FORWARD 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
2534PUBLIC void tcp_mtu_exceeded(tcp_conn)
2535tcp_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
2599PUBLIC void tcp_mtu_incr(tcp_conn)
2600tcp_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/*
2633tcp_setup_conn
2634*/
2635
2636PRIVATE void tcp_setup_conn(tcp_port, tcp_conn)
2637tcp_port_t *tcp_port;
2638tcp_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
2713PRIVATE 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 */
Note: See TracBrowser for help on using the repository browser.