source: trunk/minix/servers/inet/generic/tcp_send.c@ 20

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

Minix 3.1.2a

File size: 32.8 KB
RevLine 
[9]1/*
2tcp_send.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#include "sr.h"
13
14#include "assert.h"
15#include "io.h"
16#include "ip.h"
17#include "tcp.h"
18#include "tcp_int.h"
19
20THIS_FILE
21
22FORWARD acc_t *make_pack ARGS(( tcp_conn_t *tcp_conn ));
23FORWARD void tcp_send_timeout ARGS(( int conn, struct timer *timer ));
24FORWARD void do_snd_event ARGS(( event_t *ev, ev_arg_t arg ));
25
26PUBLIC void tcp_conn_write (tcp_conn, enq)
27tcp_conn_t *tcp_conn;
28int enq; /* Writes need to be enqueued. */
29{
30 tcp_port_t *tcp_port;
31 ev_arg_t snd_arg;
32
33 assert (tcp_conn->tc_flags & TCF_INUSE);
34
35 tcp_port= tcp_conn->tc_port;
36 if (tcp_conn->tc_flags & TCF_MORE2WRITE)
37 return;
38
39 /* Do we really have something to send here? */
40 if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT &&
41 !(tcp_conn->tc_flags & TCF_SEND_ACK) &&
42 !tcp_conn->tc_frag2send)
43 {
44 return;
45 }
46
47 tcp_conn->tc_flags |= TCF_MORE2WRITE;
48 tcp_conn->tc_send_link= NULL;
49 if (!tcp_port->tp_snd_head)
50 {
51 tcp_port->tp_snd_head= tcp_conn;
52 tcp_port->tp_snd_tail= tcp_conn;
53 if (enq)
54 {
55 snd_arg.ev_ptr= tcp_port;
56 if (!ev_in_queue(&tcp_port->tp_snd_event))
57 {
58 ev_enqueue(&tcp_port->tp_snd_event,
59 do_snd_event, snd_arg);
60 }
61 }
62 else
63 tcp_port_write(tcp_port);
64 }
65 else
66 {
67 tcp_port->tp_snd_tail->tc_send_link= tcp_conn;
68 tcp_port->tp_snd_tail= tcp_conn;
69 }
70}
71
72PRIVATE void do_snd_event(ev, arg)
73event_t *ev;
74ev_arg_t arg;
75{
76 tcp_port_t *tcp_port;
77
78 tcp_port= arg.ev_ptr;
79
80 assert(ev == &tcp_port->tp_snd_event);
81 tcp_port_write(tcp_port);
82}
83
84PUBLIC void tcp_port_write(tcp_port)
85tcp_port_t *tcp_port;
86{
87 tcp_conn_t *tcp_conn;
88 acc_t *pack2write;
89 int r;
90
91 assert (!(tcp_port->tp_flags & TPF_WRITE_IP));
92
93 while(tcp_port->tp_snd_head)
94 {
95 tcp_conn= tcp_port->tp_snd_head;
96 assert(tcp_conn->tc_flags & TCF_MORE2WRITE);
97
98 for(;;)
99 {
100 if (tcp_conn->tc_frag2send)
101 {
102 pack2write= tcp_conn->tc_frag2send;
103 tcp_conn->tc_frag2send= 0;
104 }
105 else
106 {
107 tcp_conn->tc_busy++;
108 pack2write= make_pack(tcp_conn);
109 tcp_conn->tc_busy--;
110 if (!pack2write)
111 break;
112 }
113 r= ip_send(tcp_port->tp_ipfd, pack2write,
114 bf_bufsize(pack2write));
115 if (r != NW_OK)
116 {
117 if (r == NW_WOULDBLOCK)
118 break;
119 if (r == EPACKSIZE)
120 {
121 tcp_mtu_exceeded(tcp_conn);
122 continue;
123 }
124 if (r == EDSTNOTRCH)
125 {
126 tcp_notreach(tcp_conn);
127 continue;
128 }
129 if (r == EBADDEST)
130 continue;
131 }
132 assert(r == NW_OK ||
133 (printf("ip_send failed, error %d\n", r),0));
134 }
135
136 if (pack2write)
137 {
138 tcp_port->tp_flags |= TPF_WRITE_IP;
139 tcp_port->tp_pack= pack2write;
140
141 r= ip_write (tcp_port->tp_ipfd,
142 bf_bufsize(pack2write));
143 if (r == NW_SUSPEND)
144 {
145 tcp_port->tp_flags |= TPF_WRITE_SP;
146 return;
147 }
148 assert(r == NW_OK);
149 tcp_port->tp_flags &= ~TPF_WRITE_IP;
150 assert(!(tcp_port->tp_flags &
151 (TPF_WRITE_IP|TPF_WRITE_SP)));
152 continue;
153 }
154 tcp_conn->tc_flags &= ~TCF_MORE2WRITE;
155 tcp_port->tp_snd_head= tcp_conn->tc_send_link;
156
157 }
158}
159
160PRIVATE acc_t *make_pack(tcp_conn)
161tcp_conn_t *tcp_conn;
162{
163 acc_t *pack2write, *tmp_pack, *tcp_pack;
164 tcp_hdr_t *tcp_hdr;
165 ip_hdr_t *ip_hdr;
166 int tot_hdr_size, ip_hdr_len, no_push, head, more2write;
167 u32_t seg_seq, seg_lo_data, queue_lo_data, seg_hi, seg_hi_data;
168 u16_t seg_up, mss;
169 u8_t seg_flags;
170 size_t pack_size;
171 clock_t curr_time, new_dis;
172 u8_t *optptr;
173
174 mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
175
176 assert(tcp_conn->tc_busy);
177 curr_time= get_time();
178 switch (tcp_conn->tc_state)
179 {
180 case TCS_CLOSED:
181 case TCS_LISTEN:
182 return NULL;
183 case TCS_SYN_RECEIVED:
184 case TCS_SYN_SENT:
185
186 if (tcp_conn->tc_SND_TRM == tcp_conn->tc_SND_NXT &&
187 !(tcp_conn->tc_flags & TCF_SEND_ACK))
188 {
189 return 0;
190 }
191
192 tcp_conn->tc_flags &= ~TCF_SEND_ACK;
193
194 /* Advertise a mss based on the port mtu. The current mtu may
195 * be lower if the other side sends a smaller mss.
196 */
197 mss= tcp_conn->tc_port->tp_mtu-IP_TCP_MIN_HDR_SIZE;
198
199 /* Include a max segment size option. */
200 assert(tcp_conn->tc_tcpopt == NULL);
201 tcp_conn->tc_tcpopt= bf_memreq(4);
202 optptr= (u8_t *)ptr2acc_data(tcp_conn->tc_tcpopt);
203 optptr[0]= TCP_OPT_MSS;
204 optptr[1]= 4;
205 optptr[2]= mss >> 8;
206 optptr[3]= mss & 0xFF;
207
208 pack2write= tcp_make_header(tcp_conn, &ip_hdr, &tcp_hdr,
209 (acc_t *)0);
210
211 bf_afree(tcp_conn->tc_tcpopt);
212 tcp_conn->tc_tcpopt= NULL;
213
214 if (!pack2write)
215 {
216 DBLOCK(1, printf("connection closed while inuse\n"));
217 return 0;
218 }
219 tot_hdr_size= bf_bufsize(pack2write);
220 seg_seq= tcp_conn->tc_SND_TRM;
221 if (tcp_conn->tc_state == TCS_SYN_SENT)
222 seg_flags= 0;
223 else
224 seg_flags= THF_ACK; /* except for TCS_SYN_SENT
225 * ack is always present */
226
227 if (seg_seq == tcp_conn->tc_ISS)
228 {
229 assert(tcp_conn->tc_transmit_timer.tim_active ||
230 (tcp_print_conn(tcp_conn), printf("\n"), 0));
231 seg_flags |= THF_SYN;
232 tcp_conn->tc_SND_TRM++;
233 }
234
235 tcp_hdr->th_seq_nr= htonl(seg_seq);
236 tcp_hdr->th_ack_nr= htonl(tcp_conn->tc_RCV_NXT);
237 tcp_hdr->th_flags= seg_flags;
238 tcp_hdr->th_window= htons(mss);
239 /* Initially we allow one segment */
240
241 ip_hdr->ih_length= htons(tot_hdr_size);
242
243 pack2write->acc_linkC++;
244 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
245 tcp_pack= bf_delhead(pack2write, ip_hdr_len);
246 tcp_hdr->th_chksum= ~tcp_pack_oneCsum(ip_hdr, tcp_pack);
247 bf_afree(tcp_pack);
248
249 new_dis= curr_time + 2*HZ*tcp_conn->tc_ttl;
250 if (new_dis > tcp_conn->tc_senddis)
251 tcp_conn->tc_senddis= new_dis;
252 return pack2write;
253
254 case TCS_ESTABLISHED:
255 case TCS_CLOSING:
256 seg_seq= tcp_conn->tc_SND_TRM;
257
258 seg_flags= 0;
259 pack2write= 0;
260 seg_up= 0;
261 if (tcp_conn->tc_flags & TCF_SEND_ACK)
262 {
263 seg_flags= THF_ACK;
264 tcp_conn->tc_flags &= ~TCF_SEND_ACK;
265
266 pack2write= tcp_make_header (tcp_conn, &ip_hdr,
267 &tcp_hdr, (acc_t *)0);
268 if (!pack2write)
269 {
270 return NULL;
271 }
272 }
273
274 if (tcp_conn->tc_SND_UNA != tcp_conn->tc_SND_NXT)
275 {
276 assert(tcp_LEmod4G(seg_seq, tcp_conn->tc_SND_NXT));
277
278 if (seg_seq == tcp_conn->tc_snd_cwnd)
279 {
280 DBLOCK(2,
281 printf("no data: window is closed\n"));
282 goto after_data;
283 }
284
285 /* Assert that our SYN has been ACKed. */
286 assert(tcp_conn->tc_SND_UNA != tcp_conn->tc_ISS);
287
288 seg_lo_data= seg_seq;
289 queue_lo_data= tcp_conn->tc_SND_UNA;
290
291 seg_hi= tcp_conn->tc_SND_NXT;
292 seg_hi_data= seg_hi;
293 if (tcp_conn->tc_flags & TCF_FIN_SENT)
294 {
295 if (seg_seq != seg_hi)
296 seg_flags |= THF_FIN;
297 if (queue_lo_data == seg_hi_data)
298 queue_lo_data--;
299 if (seg_lo_data == seg_hi_data)
300 seg_lo_data--;
301 seg_hi_data--;
302 }
303
304 if (!pack2write)
305 {
306 pack2write= tcp_make_header (tcp_conn,
307 &ip_hdr, &tcp_hdr, (acc_t *)0);
308 if (!pack2write)
309 {
310 return NULL;
311 }
312 }
313
314 tot_hdr_size= bf_bufsize(pack2write);
315
316 no_push= (tcp_LEmod4G(tcp_conn->tc_SND_PSH, seg_seq));
317 head= (seg_seq == tcp_conn->tc_SND_UNA);
318 if (no_push)
319 {
320 /* Shutdown sets SND_PSH */
321 seg_flags &= ~THF_FIN;
322 if (seg_hi_data-seg_lo_data <= 1)
323 {
324 /* Allways keep at least one byte
325 * for a future push.
326 */
327 DBLOCK(0x20,
328 printf("no data: no push\n"));
329 if (head)
330 {
331 DBLOCK(0x1, printf(
332 "no data: setting TCF_NO_PUSH\n"));
333 tcp_conn->tc_flags |=
334 TCF_NO_PUSH;
335 }
336 goto after_data;
337 }
338 seg_hi_data--;
339 }
340
341 if (tot_hdr_size != IP_TCP_MIN_HDR_SIZE)
342 {
343 printf(
344 "tcp_write`make_pack: tot_hdr_size = %d\n",
345 tot_hdr_size);
346 mss= tcp_conn->tc_mtu-tot_hdr_size;
347 }
348 if (seg_hi_data - seg_lo_data > mss)
349 {
350 /* Truncate to at most one segment */
351 seg_hi_data= seg_lo_data + mss;
352 seg_hi= seg_hi_data;
353 seg_flags &= ~THF_FIN;
354 }
355
356 if (no_push &&
357 seg_hi_data-seg_lo_data != mss)
358 {
359 DBLOCK(0x20, printf(
360 "no data: no push for partial segment\n"));
361 more2write= (tcp_conn->tc_fd &&
362 (tcp_conn->tc_fd->tf_flags &
363 TFF_WRITE_IP));
364 DIFBLOCK(2, more2write,
365 printf(
366 "tcp_send`make_pack: more2write -> !TCF_NO_PUSH\n");
367 );
368 if (head && !more2write)
369 {
370 DBLOCK(0x1, printf(
371 "partial segment: setting TCF_NO_PUSH\n"));
372 tcp_conn->tc_flags |= TCF_NO_PUSH;
373 }
374 goto after_data;
375 }
376
377
378 if (tcp_Gmod4G(seg_hi, tcp_conn->tc_snd_cwnd))
379 {
380 seg_hi_data= tcp_conn->tc_snd_cwnd;
381 seg_hi= seg_hi_data;
382 seg_flags &= ~THF_FIN;
383 }
384
385 if (!head &&
386 seg_hi_data-seg_lo_data < mss)
387 {
388 if (tcp_conn->tc_flags & TCF_PUSH_NOW)
389 {
390 DBLOCK(0x20,
391 printf("push: no Nagle\n"));
392 }
393 else
394 {
395 DBLOCK(0x20,
396 printf("no data: partial packet\n"));
397 seg_flags &= ~THF_FIN;
398 goto after_data;
399 }
400 }
401
402 if (seg_hi-seg_seq == 0)
403 {
404 DBLOCK(0x20,
405 printf("no data: no data available\n"));
406 goto after_data;
407 }
408
409 if (tcp_GEmod4G(tcp_conn->tc_SND_UP, seg_lo_data))
410 {
411 extern int killer_inet;
412
413 if (tcp_GEmod4G(tcp_conn->tc_SND_UP,
414 seg_hi_data))
415 {
416 seg_up= seg_hi_data-seg_seq;
417 }
418 else
419 {
420 seg_up= tcp_conn->tc_SND_UP-seg_seq;
421 }
422 seg_flags |= THF_URG;
423 if (!killer_inet &&
424 (tcp_conn->tc_flags & TCF_BSD_URG) &&
425 seg_up == 0)
426 {
427 /* A zero urgent pointer doesn't mean
428 * anything when BSD semantics are
429 * used (urgent pointer points to the
430 * first no urgent byte). The use of
431 * a zero urgent pointer also crashes
432 * a Solaris 2.3 kernel. If urgent
433 * pointer doesn't have BSD semantics
434 * then an urgent pointer of zero
435 * simply indicates that there is one
436 * urgent byte.
437 */
438 seg_flags &= ~THF_URG;
439 }
440 }
441 else
442 seg_up= 0;
443
444 if (tcp_Gmod4G(tcp_conn->tc_SND_PSH, seg_lo_data) &&
445 tcp_LEmod4G(tcp_conn->tc_SND_PSH, seg_hi_data))
446 {
447 seg_flags |= THF_PSH;
448 }
449
450 tcp_conn->tc_SND_TRM= seg_hi;
451
452 assert(tcp_conn->tc_transmit_timer.tim_active ||
453 (tcp_print_conn(tcp_conn), printf("\n"), 0));
454 if (tcp_conn->tc_rt_seq == 0 &&
455 tcp_Gmod4G(seg_seq, tcp_conn->tc_rt_threshold))
456 {
457 tcp_conn->tc_rt_time= curr_time;
458 tcp_conn->tc_rt_seq=
459 tcp_conn->tc_rt_threshold= seg_seq;
460 }
461
462 if (seg_hi_data-seg_lo_data)
463 {
464#if DEBUG & 0
465 assert(tcp_check_conn(tcp_conn));
466 assert((seg_hi_data-queue_lo_data <=
467 bf_bufsize(tcp_conn->tc_send_data) &&
468 seg_lo_data-queue_lo_data <=
469 bf_bufsize(tcp_conn->tc_send_data) &&
470 seg_hi_data>seg_lo_data)||
471 (tcp_print_conn(tcp_conn),
472 printf(
473 " seg_hi_data= 0x%x, seg_lo_data= 0x%x, queue_lo_data= 0x%x\n",
474 seg_hi_data, seg_lo_data,
475 queue_lo_data), 0));
476#endif
477
478 tmp_pack= pack2write;
479 while (tmp_pack->acc_next)
480 tmp_pack= tmp_pack->acc_next;
481 tmp_pack->acc_next=
482 bf_cut(tcp_conn->tc_send_data,
483 (unsigned)(seg_lo_data-queue_lo_data),
484 (unsigned) (seg_hi_data-seg_lo_data));
485 }
486 seg_flags |= THF_ACK;
487 }
488
489after_data:
490 if (!(seg_flags & THF_ACK))
491 {
492 if (pack2write)
493 bf_afree(pack2write);
494 return NULL;
495 }
496
497 tcp_hdr->th_seq_nr= htonl(seg_seq);
498 tcp_hdr->th_ack_nr= htonl(tcp_conn->tc_RCV_NXT);
499 tcp_hdr->th_flags= seg_flags;
500 tcp_hdr->th_window= htons(tcp_conn->tc_RCV_HI -
501 tcp_conn->tc_RCV_NXT);
502 tcp_hdr->th_urgptr= htons(seg_up);
503
504 pack_size= bf_bufsize(pack2write);
505 ip_hdr->ih_length= htons(pack_size);
506
507 pack2write->acc_linkC++;
508 ip_hdr_len= (ip_hdr->ih_vers_ihl & IH_IHL_MASK) << 2;
509 tcp_pack= bf_delhead(pack2write, ip_hdr_len);
510 tcp_hdr->th_chksum= ~tcp_pack_oneCsum(ip_hdr, tcp_pack);
511 bf_afree(tcp_pack);
512
513 new_dis= curr_time + 2*HZ*tcp_conn->tc_ttl;
514 if (new_dis > tcp_conn->tc_senddis)
515 tcp_conn->tc_senddis= new_dis;
516
517 return pack2write;
518 default:
519 DBLOCK(1, tcp_print_conn(tcp_conn); printf("\n"));
520 ip_panic(( "Illegal state" ));
521 }
522 assert(0);
523 return NULL;
524}
525
526/*
527tcp_release_retrans
528*/
529
530PUBLIC void tcp_release_retrans(tcp_conn, seg_ack, new_win)
531tcp_conn_t *tcp_conn;
532u32_t seg_ack;
533u16_t new_win;
534{
535 tcp_fd_t *tcp_fd;
536 size_t size, offset;
537 acc_t *pack;
538 clock_t retrans_time, curr_time, rtt, artt, drtt, srtt;
539 u32_t queue_lo, queue_hi;
540 u16_t mss, cthresh;
541 unsigned window;
542
543 DBLOCK(0x10, printf("tcp_release_retrans, conn[%d]: ack %lu, win %u\n",
544 tcp_conn-tcp_conn_table, (unsigned long)seg_ack, new_win););
545
546 assert(tcp_conn->tc_busy);
547 assert (tcp_GEmod4G(seg_ack, tcp_conn->tc_SND_UNA));
548 assert (tcp_LEmod4G(seg_ack, tcp_conn->tc_SND_NXT));
549
550 tcp_conn->tc_snd_dack= 0;
551 mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
552
553 curr_time= get_time();
554 if (tcp_conn->tc_rt_seq != 0 &&
555 tcp_Gmod4G(seg_ack, tcp_conn->tc_rt_seq))
556 {
557 assert(curr_time >= tcp_conn->tc_rt_time);
558 retrans_time= curr_time-tcp_conn->tc_rt_time;
559 rtt= tcp_conn->tc_rtt;
560
561 tcp_conn->tc_rt_seq= 0;
562
563 if (rtt == TCP_RTT_GRAN*CLOCK_GRAN &&
564 retrans_time <= TCP_RTT_GRAN*CLOCK_GRAN)
565 {
566 /* Common in fast networks. Nothing to do. */
567 }
568 else
569 {
570 srtt= retrans_time * TCP_RTT_SCALE;
571
572 artt= tcp_conn->tc_artt;
573 artt= ((TCP_RTT_SMOOTH-1)*artt+srtt)/TCP_RTT_SMOOTH;
574
575 srtt -= artt;
576 if (srtt < 0)
577 srtt= -srtt;
578 drtt= tcp_conn->tc_drtt;
579 drtt= ((TCP_RTT_SMOOTH-1)*drtt+srtt)/TCP_RTT_SMOOTH;
580
581 rtt= (artt+TCP_DRTT_MULT*drtt-1)/TCP_RTT_SCALE+1;
582 if (rtt < TCP_RTT_GRAN*CLOCK_GRAN)
583 {
584 rtt= TCP_RTT_GRAN*CLOCK_GRAN;
585 }
586 else if (rtt > TCP_RTT_MAX)
587 {
588#if DEBUG
589 static int warned /* = 0 */;
590
591 if (!warned)
592 {
593 printf(
594"tcp_release_retrans: warning retransmission time is limited to %d ms\n",
595 TCP_RTT_MAX*1000/HZ);
596 warned= 1;
597 }
598#endif
599 rtt= TCP_RTT_MAX;
600 }
601 DBLOCK(0x10, printf(
602 "tcp_release_retrans, conn[%d]: retrans_time= %ld ms, rtt = %ld ms\n",
603 tcp_conn-tcp_conn_table,
604 retrans_time*1000/HZ,
605 rtt*1000/HZ));
606
607 DBLOCK(0x10, printf(
608 "tcp_release_retrans: artt= %ld -> %ld, drtt= %ld -> %ld\n",
609 tcp_conn->tc_artt, artt,
610 tcp_conn->tc_drtt, drtt));
611
612 tcp_conn->tc_artt= artt;
613 tcp_conn->tc_drtt= drtt;
614 tcp_conn->tc_rtt= rtt;
615 }
616
617 if (tcp_conn->tc_mtu != tcp_conn->tc_max_mtu &&
618 curr_time > tcp_conn->tc_mtutim+TCP_PMTU_INCR_IV)
619 {
620 tcp_mtu_incr(tcp_conn);
621 }
622 }
623
624 /* Update the current window. */
625 window= tcp_conn->tc_snd_cwnd-tcp_conn->tc_SND_UNA;
626 assert(seg_ack != tcp_conn->tc_SND_UNA);
627
628 /* For every real ACK we try to increase the current window
629 * with 1 mss.
630 */
631 window += mss;
632
633 /* If the window becomes larger than the current threshold,
634 * increment the threshold by a small amount and set the
635 * window to the threshold.
636 */
637 cthresh= tcp_conn->tc_snd_cthresh;
638 if (window > cthresh)
639 {
640 cthresh += tcp_conn->tc_snd_cinc;
641 tcp_conn->tc_snd_cthresh= cthresh;
642 window= cthresh;
643 }
644
645 /* If the window is larger than the window advertised by the
646 * receiver, set the window size to the advertisement.
647 */
648 if (window > new_win)
649 window= new_win;
650
651 tcp_conn->tc_snd_cwnd= seg_ack+window;
652
653 /* Release data queued for retransmissions. */
654 queue_lo= tcp_conn->tc_SND_UNA;
655 queue_hi= tcp_conn->tc_SND_NXT;
656
657 tcp_conn->tc_SND_UNA= seg_ack;
658 if (tcp_Lmod4G(tcp_conn->tc_SND_TRM, seg_ack))
659 {
660 tcp_conn->tc_SND_TRM= seg_ack;
661 }
662 assert(tcp_GEmod4G(tcp_conn->tc_snd_cwnd, seg_ack));
663
664 /* Advance ISS every 0.5GB to avoid problem with wrap around */
665 if (tcp_conn->tc_SND_UNA - tcp_conn->tc_ISS > 0x40000000)
666 {
667 tcp_conn->tc_ISS += 0x20000000;
668 DBLOCK(1, printf(
669 "tcp_release_retrans: updating ISS to 0x%lx\n",
670 (unsigned long)tcp_conn->tc_ISS););
671 if (tcp_Lmod4G(tcp_conn->tc_SND_UP, tcp_conn->tc_ISS))
672 {
673 tcp_conn->tc_SND_UP= tcp_conn->tc_ISS;
674 DBLOCK(1, printf(
675 "tcp_release_retrans: updating SND_UP to 0x%lx\n",
676 (unsigned long)tcp_conn->tc_SND_UP););
677 }
678 }
679
680 if (queue_lo == tcp_conn->tc_ISS)
681 queue_lo++;
682
683 if (tcp_conn->tc_flags & TCF_FIN_SENT)
684 {
685 if (seg_ack == queue_hi)
686 seg_ack--;
687 if (queue_lo == queue_hi)
688 queue_lo--;
689 queue_hi--;
690 }
691
692 offset= seg_ack - queue_lo;
693 size= queue_hi - seg_ack;
694 pack= tcp_conn->tc_send_data;
695 tcp_conn->tc_send_data= 0;
696
697 if (!size)
698 {
699 bf_afree(pack);
700 }
701 else
702 {
703 pack= bf_delhead(pack, offset);
704 tcp_conn->tc_send_data= pack;
705 }
706
707 if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_snd_cwnd))
708 tcp_conn->tc_SND_TRM= tcp_conn->tc_snd_cwnd;
709
710 /* Copy in new data if an ioctl is pending or if a write request is
711 * pending and either the write can be completed or at least one
712 * mss buffer space is available.
713 */
714 tcp_fd= tcp_conn->tc_fd;
715 if (tcp_fd)
716 {
717 if (tcp_fd->tf_flags & TFF_IOCTL_IP)
718 {
719 tcp_fd_write(tcp_conn);
720 }
721 if ((tcp_fd->tf_flags & TFF_WRITE_IP) &&
722 (size+tcp_fd->tf_write_count <= TCP_MAX_SND_WND_SIZE ||
723 size <= TCP_MAX_SND_WND_SIZE-mss))
724 {
725 tcp_fd_write(tcp_conn);
726 }
727 if (tcp_fd->tf_flags & TFF_SEL_WRITE)
728 tcp_rsel_write(tcp_conn);
729 }
730 else
731 {
732 if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
733 {
734 assert(tcp_conn->tc_state == TCS_CLOSING);
735 DBLOCK(0x10,
736 printf("all data sent in abondoned connection\n"));
737 tcp_close_connection(tcp_conn, ENOTCONN);
738 return;
739 }
740 }
741
742 if (!size && !tcp_conn->tc_send_data)
743 {
744 /* Reset window if a write is completed */
745 tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA + mss;
746 }
747
748 DIFBLOCK(2, (tcp_conn->tc_snd_cwnd == tcp_conn->tc_SND_TRM),
749 printf("not sending: zero window\n"));
750
751 if (tcp_conn->tc_snd_cwnd != tcp_conn->tc_SND_TRM &&
752 tcp_conn->tc_SND_NXT != tcp_conn->tc_SND_TRM)
753 {
754 tcp_conn_write(tcp_conn, 1);
755 }
756
757}
758
759/*
760tcp_fast_retrans
761*/
762
763PUBLIC void tcp_fast_retrans(tcp_conn)
764tcp_conn_t *tcp_conn;
765{
766 u16_t mss, mss2;
767
768 /* Update threshold sequence number for retransmission calculation. */
769 if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_rt_threshold))
770 tcp_conn->tc_rt_threshold= tcp_conn->tc_SND_TRM;
771
772 tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
773
774 mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
775 mss2= 2*mss;
776
777 if (tcp_conn->tc_snd_cwnd == tcp_conn->tc_SND_UNA)
778 tcp_conn->tc_snd_cwnd++;
779 if (tcp_Gmod4G(tcp_conn->tc_snd_cwnd, tcp_conn->tc_SND_UNA + mss2))
780 {
781 tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA + mss2;
782 if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_snd_cwnd))
783 tcp_conn->tc_SND_TRM= tcp_conn->tc_snd_cwnd;
784
785 tcp_conn->tc_snd_cthresh /= 2;
786 if (tcp_conn->tc_snd_cthresh < mss2)
787 tcp_conn->tc_snd_cthresh= mss2;
788 }
789
790 tcp_conn_write(tcp_conn, 1);
791}
792
793#if 0
794PUBLIC void do_tcp_timeout(tcp_conn)
795tcp_conn_t *tcp_conn;
796{
797 tcp_send_timeout(tcp_conn-tcp_conn_table,
798 &tcp_conn->tc_transmit_timer);
799}
800#endif
801
802/*
803tcp_send_timeout
804*/
805
806PRIVATE void tcp_send_timeout(conn, timer)
807int conn;
808struct timer *timer;
809{
810 tcp_conn_t *tcp_conn;
811 u16_t mss, mss2;
812 u32_t snd_una, snd_nxt;
813 clock_t curr_time, rtt, stt, timeout;
814 acc_t *pkt;
815 int new_ttl, no_push;
816
817 DBLOCK(0x20, printf("tcp_send_timeout: conn[%d]\n", conn));
818
819 curr_time= get_time();
820
821 tcp_conn= &tcp_conn_table[conn];
822 assert(tcp_conn->tc_flags & TCF_INUSE);
823 assert(tcp_conn->tc_state != TCS_CLOSED);
824 assert(tcp_conn->tc_state != TCS_LISTEN);
825
826 snd_una= tcp_conn->tc_SND_UNA;
827 snd_nxt= tcp_conn->tc_SND_NXT;
828 no_push= (tcp_conn->tc_flags & TCF_NO_PUSH);
829 if (snd_nxt == snd_una || no_push)
830 {
831 /* Nothing more to send */
832 assert(tcp_conn->tc_SND_TRM == snd_una || no_push);
833
834 /* A new write sets the timer if tc_transmit_seq == SND_UNA */
835 tcp_conn->tc_transmit_seq= tcp_conn->tc_SND_UNA;
836 tcp_conn->tc_stt= 0;
837 tcp_conn->tc_0wnd_to= 0;
838 assert(!tcp_conn->tc_fd ||
839 !(tcp_conn->tc_fd->tf_flags & TFF_WRITE_IP) ||
840 (tcp_print_conn(tcp_conn), printf("\n"), 0));
841
842 if (snd_nxt != snd_una)
843 {
844 assert(no_push);
845 DBLOCK(1, printf("not setting keepalive timer\n"););
846
847 /* No point in setting the keepalive timer if we
848 * still have to send more data.
849 */
850 return;
851 }
852
853 assert(tcp_conn->tc_send_data == NULL);
854 DBLOCK(0x20, printf("keep alive timer\n"));
855 if (tcp_conn->tc_ka_snd != tcp_conn->tc_SND_NXT ||
856 tcp_conn->tc_ka_rcv != tcp_conn->tc_RCV_NXT)
857 {
858 tcp_conn->tc_ka_snd= tcp_conn->tc_SND_NXT;
859 tcp_conn->tc_ka_rcv= tcp_conn->tc_RCV_NXT;
860 DBLOCK(0x20, printf(
861"tcp_send_timeout: conn[%d] setting keepalive timer (+%ld ms)\n",
862 tcp_conn-tcp_conn_table,
863 tcp_conn->tc_ka_time*1000/HZ));
864 clck_timer(&tcp_conn->tc_transmit_timer,
865 curr_time+tcp_conn->tc_ka_time,
866 tcp_send_timeout,
867 tcp_conn-tcp_conn_table);
868 return;
869 }
870 DBLOCK(0x10, printf(
871 "tcp_send_timeout, conn[%d]: triggering keep alive probe\n",
872 tcp_conn-tcp_conn_table));
873 tcp_conn->tc_ka_snd--;
874 if (!(tcp_conn->tc_flags & TCF_FIN_SENT))
875 {
876 pkt= bf_memreq(1);
877 *ptr2acc_data(pkt)= '\xff'; /* a random char */
878 tcp_conn->tc_send_data= pkt; pkt= NULL;
879 }
880 tcp_conn->tc_SND_UNA--;
881 if (tcp_conn->tc_SND_UNA == tcp_conn->tc_ISS)
882 {
883 /* We didn't send anything so far. Retrying the
884 * SYN is too hard. Decrement ISS and hope
885 * that the other side doesn't care.
886 */
887 tcp_conn->tc_ISS--;
888 }
889
890 /* Set tc_transmit_seq and tc_stt to trigger packet */
891 tcp_conn->tc_transmit_seq= tcp_conn->tc_SND_UNA;
892 tcp_conn->tc_stt= curr_time;
893
894 /* Set tc_rt_seq for round trip measurements */
895 tcp_conn->tc_rt_time= curr_time;
896 tcp_conn->tc_rt_seq= tcp_conn->tc_SND_UNA;
897
898 /* Set PSH to make sure that data gets sent */
899 tcp_conn->tc_SND_PSH= tcp_conn->tc_SND_NXT;
900 assert(tcp_check_conn(tcp_conn));
901
902 /* Fall through */
903 }
904
905 rtt= tcp_conn->tc_rtt;
906
907 if (tcp_conn->tc_transmit_seq != tcp_conn->tc_SND_UNA)
908 {
909 /* Some data has been acknowledged since the last time the
910 * timer was set, set the timer again. */
911 tcp_conn->tc_transmit_seq= tcp_conn->tc_SND_UNA;
912 tcp_conn->tc_stt= 0;
913 tcp_conn->tc_0wnd_to= 0;
914
915 DBLOCK(0x20, printf(
916 "tcp_send_timeout: conn[%d] setting timer to %ld ms (+%ld ms)\n",
917 tcp_conn-tcp_conn_table,
918 (curr_time+rtt)*1000/HZ, rtt*1000/HZ));
919
920 clck_timer(&tcp_conn->tc_transmit_timer,
921 curr_time+rtt, tcp_send_timeout,
922 tcp_conn-tcp_conn_table);
923 return;
924 }
925
926 stt= tcp_conn->tc_stt;
927 if (stt == 0)
928 {
929 /* Some packet arrived but did not acknowledge any data.
930 * Apparently, the other side is still alive and has a
931 * reason to transmit. We can asume a zero window.
932 */
933
934 DBLOCK(0x10, printf("conn[%d] setting zero window timer\n",
935 tcp_conn-tcp_conn_table));
936
937 if (tcp_conn->tc_0wnd_to < TCP_0WND_MIN)
938 tcp_conn->tc_0wnd_to= TCP_0WND_MIN;
939 else if (tcp_conn->tc_0wnd_to < rtt)
940 tcp_conn->tc_0wnd_to= rtt;
941 else
942 {
943 tcp_conn->tc_0wnd_to *= 2;
944 if (tcp_conn->tc_0wnd_to > TCP_0WND_MAX)
945 tcp_conn->tc_0wnd_to= TCP_0WND_MAX;
946 }
947 tcp_conn->tc_stt= curr_time;
948 tcp_conn->tc_rt_seq= 0;
949
950 DBLOCK(0x10, printf(
951 "tcp_send_timeout: conn[%d] setting timer to %ld ms (+%ld ms)\n",
952 tcp_conn-tcp_conn_table,
953 (curr_time+tcp_conn->tc_0wnd_to)*1000/HZ,
954 tcp_conn->tc_0wnd_to*1000/HZ));
955
956 clck_timer(&tcp_conn->tc_transmit_timer,
957 curr_time+tcp_conn->tc_0wnd_to,
958 tcp_send_timeout, tcp_conn-tcp_conn_table);
959 return;
960 }
961 assert(stt <= curr_time);
962
963 DIFBLOCK(0x10, (tcp_conn->tc_fd == 0),
964 printf("conn[%d] timeout in abondoned connection\n",
965 tcp_conn-tcp_conn_table));
966
967 /* At this point, we have do a retransmission, or send a zero window
968 * probe, which is almost the same.
969 */
970
971 DBLOCK(0x20, printf("tcp_send_timeout: conn[%d] una= %lu, rtt= %ldms\n",
972 tcp_conn-tcp_conn_table,
973 (unsigned long)tcp_conn->tc_SND_UNA, rtt*1000/HZ));
974
975 /* Update threshold sequence number for retransmission calculation. */
976 if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_rt_threshold))
977 tcp_conn->tc_rt_threshold= tcp_conn->tc_SND_TRM;
978
979 tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_UNA;
980
981 if (tcp_conn->tc_flags & TCF_PMTU &&
982 curr_time > stt+TCP_PMTU_BLACKHOLE)
983 {
984 /* We can't tell the difference between a PMTU blackhole
985 * and a broken link. Assume a PMTU blackhole, and switch
986 * off PMTU discovery.
987 */
988 DBLOCK(1, printf(
989 "tcp[%d]: PMTU blackhole (or broken link) on route to ",
990 tcp_conn-tcp_conn_table);
991 writeIpAddr(tcp_conn->tc_remaddr);
992 printf(", max mtu = %u\n", tcp_conn->tc_max_mtu););
993 tcp_conn->tc_flags &= ~TCF_PMTU;
994 tcp_conn->tc_mtutim= curr_time;
995 if (tcp_conn->tc_max_mtu > IP_DEF_MTU)
996 tcp_conn->tc_mtu= IP_DEF_MTU;
997 }
998
999 mss= tcp_conn->tc_mtu-IP_TCP_MIN_HDR_SIZE;
1000 mss2= 2*mss;
1001
1002 if (tcp_conn->tc_snd_cwnd == tcp_conn->tc_SND_UNA)
1003 tcp_conn->tc_snd_cwnd++;
1004 if (tcp_Gmod4G(tcp_conn->tc_snd_cwnd, tcp_conn->tc_SND_UNA + mss2))
1005 {
1006 tcp_conn->tc_snd_cwnd= tcp_conn->tc_SND_UNA + mss2;
1007 if (tcp_Gmod4G(tcp_conn->tc_SND_TRM, tcp_conn->tc_snd_cwnd))
1008 tcp_conn->tc_SND_TRM= tcp_conn->tc_snd_cwnd;
1009
1010 tcp_conn->tc_snd_cthresh /= 2;
1011 if (tcp_conn->tc_snd_cthresh < mss2)
1012 tcp_conn->tc_snd_cthresh= mss2;
1013 }
1014
1015 if (curr_time-stt > tcp_conn->tc_rt_dead)
1016 {
1017 tcp_close_connection(tcp_conn, ETIMEDOUT);
1018 return;
1019 }
1020
1021 timeout= (curr_time-stt) >> 3;
1022 if (timeout < rtt)
1023 timeout= rtt;
1024 timeout += curr_time;
1025
1026 DBLOCK(0x20, printf(
1027 "tcp_send_timeout: conn[%d] setting timer to %ld ms (+%ld ms)\n",
1028 tcp_conn-tcp_conn_table, timeout*1000/HZ,
1029 (timeout-curr_time)*1000/HZ));
1030
1031 clck_timer(&tcp_conn->tc_transmit_timer, timeout,
1032 tcp_send_timeout, tcp_conn-tcp_conn_table);
1033
1034#if 0
1035 if (tcp_conn->tc_rt_seq == 0)
1036 {
1037 printf("tcp_send_timeout: conn[%d]: setting tc_rt_time\n",
1038 tcp_conn-tcp_conn_table);
1039 tcp_conn->tc_rt_time= curr_time-rtt;
1040 tcp_conn->tc_rt_seq= tcp_conn->tc_SND_UNA;
1041 }
1042#endif
1043
1044 if (tcp_conn->tc_state == TCS_SYN_SENT ||
1045 (curr_time-stt >= tcp_conn->tc_ttl*HZ))
1046 {
1047 new_ttl= tcp_conn->tc_ttl+1;
1048 if (new_ttl> IP_MAX_TTL)
1049 new_ttl= IP_MAX_TTL;
1050 tcp_conn->tc_ttl= new_ttl;
1051 }
1052
1053 tcp_conn_write(tcp_conn, 0);
1054}
1055
1056
1057PUBLIC void tcp_fd_write(tcp_conn)
1058tcp_conn_t *tcp_conn;
1059{
1060 tcp_fd_t *tcp_fd;
1061 int urg, nourg, push;
1062 u32_t max_seq;
1063 size_t max_trans, write_count;
1064 acc_t *data, *send_data;
1065
1066 assert(tcp_conn->tc_busy);
1067 tcp_fd= tcp_conn->tc_fd;
1068
1069 if ((tcp_fd->tf_flags & TFF_IOCTL_IP) &&
1070 !(tcp_fd->tf_flags & TFF_WRITE_IP))
1071 {
1072 if (tcp_fd->tf_ioreq != NWIOTCPSHUTDOWN)
1073 return;
1074 DBLOCK(0x10, printf("NWIOTCPSHUTDOWN\n"));
1075 if (tcp_conn->tc_state == TCS_CLOSED)
1076 {
1077 tcp_reply_ioctl (tcp_fd, tcp_conn->tc_error);
1078 return;
1079 }
1080 if (!(tcp_conn->tc_flags & TCF_FIN_SENT))
1081 {
1082 DBLOCK(0x10, printf("calling tcp_shutdown\n"));
1083 tcp_shutdown (tcp_conn);
1084 }
1085 else
1086 {
1087 if (tcp_conn->tc_SND_UNA == tcp_conn->tc_SND_NXT)
1088 {
1089 tcp_reply_ioctl (tcp_fd, NW_OK);
1090 DBLOCK(0x10, printf("shutdown completed\n"));
1091 }
1092 else
1093 {
1094 DBLOCK(0x10,
1095 printf("shutdown still inprogress\n"));
1096 }
1097 }
1098 return;
1099 }
1100
1101 assert (tcp_fd->tf_flags & TFF_WRITE_IP);
1102 if (tcp_conn->tc_state == TCS_CLOSED)
1103 {
1104 if (tcp_fd->tf_write_offset)
1105 {
1106 tcp_reply_write(tcp_fd,
1107 tcp_fd->tf_write_offset);
1108 }
1109 else
1110 tcp_reply_write(tcp_fd, tcp_conn->tc_error);
1111 return;
1112 }
1113
1114 urg= (tcp_fd->tf_flags & TFF_WR_URG);
1115 push= (tcp_fd->tf_flags & TFF_PUSH_DATA);
1116
1117 max_seq= tcp_conn->tc_SND_UNA + TCP_MAX_SND_WND_SIZE;
1118 max_trans= max_seq - tcp_conn->tc_SND_NXT;
1119 if (tcp_fd->tf_write_count <= max_trans)
1120 write_count= tcp_fd->tf_write_count;
1121 else
1122 write_count= max_trans;
1123 if (write_count)
1124 {
1125 if (tcp_conn->tc_flags & TCF_BSD_URG)
1126 {
1127 if (tcp_Gmod4G(tcp_conn->tc_SND_NXT,
1128 tcp_conn->tc_SND_UNA))
1129 {
1130 nourg= tcp_LEmod4G(tcp_conn->tc_SND_UP,
1131 tcp_conn->tc_SND_UNA);
1132 if ((urg && nourg) || (!urg && !nourg))
1133 {
1134 DBLOCK(0x20,
1135 printf("not sending\n"));
1136 return;
1137 }
1138 }
1139 }
1140 data= (*tcp_fd->tf_get_userdata)
1141 (tcp_fd->tf_srfd, tcp_fd->tf_write_offset,
1142 write_count, FALSE);
1143
1144 if (!data)
1145 {
1146 if (tcp_fd->tf_write_offset)
1147 {
1148 tcp_reply_write(tcp_fd,
1149 tcp_fd->tf_write_offset);
1150 }
1151 else
1152 tcp_reply_write(tcp_fd, EFAULT);
1153 return;
1154 }
1155 tcp_fd->tf_write_offset += write_count;
1156 tcp_fd->tf_write_count -= write_count;
1157
1158 send_data= tcp_conn->tc_send_data;
1159 tcp_conn->tc_send_data= 0;
1160 send_data= bf_append(send_data, data);
1161 tcp_conn->tc_send_data= send_data;
1162 tcp_conn->tc_SND_NXT += write_count;
1163 if (urg)
1164 {
1165 if (tcp_conn->tc_flags & TCF_BSD_URG)
1166 tcp_conn->tc_SND_UP= tcp_conn->tc_SND_NXT;
1167 else
1168 tcp_conn->tc_SND_UP= tcp_conn->tc_SND_NXT-1;
1169 }
1170 if (push && !tcp_fd->tf_write_count)
1171 tcp_conn->tc_SND_PSH= tcp_conn->tc_SND_NXT;
1172 }
1173 if (!tcp_fd->tf_write_count)
1174 {
1175 tcp_reply_write(tcp_fd, tcp_fd->tf_write_offset);
1176 }
1177}
1178
1179PUBLIC unsigned tcp_sel_write(tcp_conn)
1180tcp_conn_t *tcp_conn;
1181{
1182 tcp_fd_t *tcp_fd;
1183 int urg, nourg;
1184 u32_t max_seq;
1185 size_t max_trans;
1186
1187 tcp_fd= tcp_conn->tc_fd;
1188
1189 if (tcp_conn->tc_state == TCS_CLOSED)
1190 return 1;
1191
1192 urg= (tcp_fd->tf_flags & TFF_WR_URG);
1193
1194 max_seq= tcp_conn->tc_SND_UNA + TCP_MAX_SND_WND_SIZE;
1195 max_trans= max_seq - tcp_conn->tc_SND_NXT;
1196 if (max_trans)
1197 {
1198 if (tcp_conn->tc_flags & TCF_BSD_URG)
1199 {
1200 if (tcp_Gmod4G(tcp_conn->tc_SND_NXT,
1201 tcp_conn->tc_SND_UNA))
1202 {
1203 nourg= tcp_LEmod4G(tcp_conn->tc_SND_UP,
1204 tcp_conn->tc_SND_UNA);
1205 if ((urg && nourg) || (!urg && !nourg))
1206 {
1207 DBLOCK(0x20,
1208 printf("not sending\n"));
1209 return 0;
1210 }
1211 }
1212 }
1213 return 1;
1214 }
1215
1216 return 0;
1217}
1218
1219PUBLIC void
1220tcp_rsel_write(tcp_conn)
1221tcp_conn_t *tcp_conn;
1222{
1223 tcp_fd_t *tcp_fd;
1224
1225 if (tcp_sel_write(tcp_conn) == 0)
1226 return;
1227
1228 tcp_fd= tcp_conn->tc_fd;
1229 tcp_fd->tf_flags &= ~TFF_SEL_WRITE;
1230 if (tcp_fd->tf_select_res)
1231 tcp_fd->tf_select_res(tcp_fd->tf_srfd, SR_SELECT_WRITE);
1232 else
1233 printf("tcp_rsel_write: no select_res\n");
1234}
1235
1236/*
1237tcp_shutdown
1238*/
1239
1240PUBLIC void tcp_shutdown(tcp_conn)
1241tcp_conn_t *tcp_conn;
1242{
1243 switch (tcp_conn->tc_state)
1244 {
1245 case TCS_CLOSED:
1246 case TCS_LISTEN:
1247 case TCS_SYN_SENT:
1248 case TCS_SYN_RECEIVED:
1249 tcp_close_connection(tcp_conn, ENOTCONN);
1250 return;
1251 }
1252
1253 if (tcp_conn->tc_flags & TCF_FIN_SENT)
1254 return;
1255 tcp_conn->tc_flags |= TCF_FIN_SENT;
1256 tcp_conn->tc_flags &= ~TCF_NO_PUSH;
1257 tcp_conn->tc_SND_NXT++;
1258 tcp_conn->tc_SND_PSH= tcp_conn->tc_SND_NXT;
1259
1260 assert (tcp_check_conn(tcp_conn) ||
1261 (tcp_print_conn(tcp_conn), printf("\n"), 0));
1262
1263 tcp_conn_write(tcp_conn, 1);
1264
1265 /* Start the timer */
1266 tcp_set_send_timer(tcp_conn);
1267}
1268
1269PUBLIC void tcp_set_send_timer(tcp_conn)
1270tcp_conn_t *tcp_conn;
1271{
1272 clock_t curr_time;
1273 clock_t rtt;
1274
1275 assert(tcp_conn->tc_state != TCS_CLOSED);
1276 assert(tcp_conn->tc_state != TCS_LISTEN);
1277
1278 curr_time= get_time();
1279 rtt= tcp_conn->tc_rtt;
1280
1281 DBLOCK(0x20, printf(
1282 "tcp_set_send_timer: conn[%d] setting timer to %ld ms (+%ld ms)\n",
1283 tcp_conn-tcp_conn_table,
1284 (curr_time+rtt)*1000/HZ, rtt*1000/HZ));
1285
1286 /* Start the timer */
1287 clck_timer(&tcp_conn->tc_transmit_timer,
1288 curr_time+rtt, tcp_send_timeout, tcp_conn-tcp_conn_table);
1289 tcp_conn->tc_stt= curr_time;
1290}
1291
1292/*
1293tcp_close_connection
1294
1295*/
1296
1297PUBLIC void tcp_close_connection(tcp_conn, error)
1298tcp_conn_t *tcp_conn;
1299int error;
1300{
1301 int i;
1302 tcp_port_t *tcp_port;
1303 tcp_fd_t *tcp_fd;
1304 tcp_conn_t *tc;
1305
1306 assert (tcp_check_conn(tcp_conn) ||
1307 (tcp_print_conn(tcp_conn), printf("\n"), 0));
1308 assert (tcp_conn->tc_flags & TCF_INUSE);
1309
1310 tcp_conn->tc_error= error;
1311 tcp_port= tcp_conn->tc_port;
1312 tcp_fd= tcp_conn->tc_fd;
1313 if (tcp_conn->tc_state == TCS_CLOSED)
1314 return;
1315
1316 tcp_conn->tc_state= TCS_CLOSED;
1317 DBLOCK(0x10, tcp_print_state(tcp_conn); printf("\n"));
1318
1319 if (tcp_fd && (tcp_fd->tf_flags & TFF_LISTENQ))
1320 {
1321 for (i= 0; i<TFL_LISTEN_MAX; i++)
1322 {
1323 if (tcp_fd->tf_listenq[i] == tcp_conn)
1324 break;
1325 }
1326 assert(i < TFL_LISTEN_MAX);
1327 tcp_fd->tf_listenq[i]= NULL;
1328
1329 assert(tcp_conn->tc_connInprogress);
1330 tcp_conn->tc_connInprogress= 0;
1331
1332 tcp_conn->tc_fd= NULL;
1333 tcp_fd= NULL;
1334 }
1335 else if (tcp_fd)
1336 {
1337
1338 tcp_conn->tc_busy++;
1339 assert(tcp_fd->tf_conn == tcp_conn);
1340
1341 if (tcp_fd->tf_flags & TFF_READ_IP)
1342 tcp_fd_read (tcp_conn, 1);
1343 assert (!(tcp_fd->tf_flags & TFF_READ_IP));
1344 if (tcp_fd->tf_flags & TFF_SEL_READ)
1345 tcp_rsel_read (tcp_conn);
1346
1347 if (tcp_fd->tf_flags & TFF_WRITE_IP)
1348 {
1349 tcp_fd_write(tcp_conn);
1350 tcp_conn_write(tcp_conn, 1);
1351 }
1352 assert (!(tcp_fd->tf_flags & TFF_WRITE_IP));
1353 if (tcp_fd->tf_flags & TFF_IOCTL_IP)
1354 {
1355 tcp_fd_write(tcp_conn);
1356 tcp_conn_write(tcp_conn, 1);
1357 }
1358 if (tcp_fd->tf_flags & TFF_IOCTL_IP)
1359 assert(tcp_fd->tf_ioreq != NWIOTCPSHUTDOWN);
1360 if (tcp_fd->tf_flags & TFF_SEL_WRITE)
1361 tcp_rsel_write(tcp_conn);
1362
1363 if (tcp_conn->tc_connInprogress)
1364 tcp_restart_connect(tcp_conn);
1365 assert (!tcp_conn->tc_connInprogress);
1366 assert (!(tcp_fd->tf_flags & TFF_IOCTL_IP) ||
1367 (printf("req= 0x%lx\n",
1368 (unsigned long)tcp_fd->tf_ioreq), 0));
1369 tcp_conn->tc_busy--;
1370 }
1371
1372 if (tcp_conn->tc_rcvd_data)
1373 {
1374 bf_afree(tcp_conn->tc_rcvd_data);
1375 tcp_conn->tc_rcvd_data= NULL;
1376 }
1377 tcp_conn->tc_flags &= ~TCF_FIN_RECV;
1378 tcp_conn->tc_RCV_LO= tcp_conn->tc_RCV_NXT;
1379
1380 if (tcp_conn->tc_adv_data)
1381 {
1382 bf_afree(tcp_conn->tc_adv_data);
1383 tcp_conn->tc_adv_data= NULL;
1384 }
1385
1386 if (tcp_conn->tc_send_data)
1387 {
1388 bf_afree(tcp_conn->tc_send_data);
1389 tcp_conn->tc_send_data= NULL;
1390 tcp_conn->tc_SND_TRM=
1391 tcp_conn->tc_SND_NXT= tcp_conn->tc_SND_UNA;
1392 }
1393 tcp_conn->tc_SND_TRM= tcp_conn->tc_SND_NXT= tcp_conn->tc_SND_UNA;
1394
1395 if (tcp_conn->tc_remipopt)
1396 {
1397 bf_afree(tcp_conn->tc_remipopt);
1398 tcp_conn->tc_remipopt= NULL;
1399 }
1400
1401 if (tcp_conn->tc_tcpopt)
1402 {
1403 bf_afree(tcp_conn->tc_tcpopt);
1404 tcp_conn->tc_tcpopt= NULL;
1405 }
1406
1407 if (tcp_conn->tc_frag2send)
1408 {
1409 bf_afree(tcp_conn->tc_frag2send);
1410 tcp_conn->tc_frag2send= NULL;
1411 }
1412 if (tcp_conn->tc_flags & TCF_MORE2WRITE)
1413 {
1414 for (tc= tcp_port->tp_snd_head; tc; tc= tc->tc_send_link)
1415 {
1416 if (tc->tc_send_link == tcp_conn)
1417 break;
1418 }
1419 if (tc == NULL)
1420 {
1421 assert(tcp_port->tp_snd_head == tcp_conn);
1422 tcp_port->tp_snd_head= tcp_conn->tc_send_link;
1423 }
1424 else
1425 {
1426 tc->tc_send_link= tcp_conn->tc_send_link;
1427 if (tc->tc_send_link == NULL)
1428 tcp_port->tp_snd_tail= tc;
1429 }
1430 tcp_conn->tc_flags &= ~TCF_MORE2WRITE;
1431 }
1432
1433 clck_untimer (&tcp_conn->tc_transmit_timer);
1434 tcp_conn->tc_transmit_seq= 0;
1435
1436 /* clear all flags but TCF_INUSE */
1437 tcp_conn->tc_flags &= TCF_INUSE;
1438 assert (tcp_check_conn(tcp_conn));
1439}
1440
1441/*
1442 * $PchId: tcp_send.c,v 1.32 2005/06/28 14:21:52 philip Exp $
1443 */
Note: See TracBrowser for help on using the repository browser.