]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/Tcp4Dxe/Tcp4Output.c
Fixed EBC build issues.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Tcp4Dxe / Tcp4Output.c
1 /** @file
2
3 Copyright (c) 2005 - 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 Tcp4Output.c
15
16 Abstract:
17
18 TCP output process routines.
19
20
21 **/
22
23 #include "Tcp4Main.h"
24
25 STATIC UINT8 mTcpOutFlag[] = {
26 0, // TCP_CLOSED
27 0, // TCP_LISTEN
28 TCP_FLG_SYN, // TCP_SYN_SENT
29 TCP_FLG_SYN | TCP_FLG_ACK, // TCP_SYN_RCVD
30 TCP_FLG_ACK, // TCP_ESTABLISHED
31 TCP_FLG_FIN | TCP_FLG_ACK, // TCP_FIN_WAIT_1
32 TCP_FLG_ACK, // TCP_FIN_WAIT_2
33 TCP_FLG_ACK | TCP_FLG_FIN, // TCP_CLOSING
34 TCP_FLG_ACK, // TCP_TIME_WAIT
35 TCP_FLG_ACK, // TCP_CLOSE_WAIT
36 TCP_FLG_FIN | TCP_FLG_ACK // TCP_LAST_ACK
37 };
38
39
40 /**
41 Compute the sequence space left in the old receive window.
42
43 @param Tcb Pointer to the TCP_CB of this TCP instance.
44
45 @return The sequence space left in the old receive window.
46
47 **/
48 UINT32
49 TcpRcvWinOld (
50 IN TCP_CB *Tcb
51 )
52 {
53 UINT32 OldWin;
54
55 OldWin = 0;
56
57 if (TCP_SEQ_GT (Tcb->RcvWl2 + Tcb->RcvWnd, Tcb->RcvNxt)) {
58
59 OldWin = TCP_SUB_SEQ (
60 Tcb->RcvWl2 + Tcb->RcvWnd,
61 Tcb->RcvNxt
62 );
63 }
64
65 return OldWin;
66 }
67
68
69 /**
70 Compute the current receive window.
71
72 @param Tcb Pointer to the TCP_CB of this TCP instance.
73
74 @return The size of the current receive window, in bytes.
75
76 **/
77 UINT32
78 TcpRcvWinNow (
79 IN TCP_CB *Tcb
80 )
81 {
82 SOCKET *Sk;
83 UINT32 Win;
84 UINT32 Increase;
85 UINT32 OldWin;
86
87 Sk = Tcb->Sk;
88 ASSERT (Sk);
89
90 OldWin = TcpRcvWinOld (Tcb);
91
92 Win = SockGetFreeSpace (Sk, SOCK_RCV_BUF);
93
94 Increase = 0;
95 if (Win > OldWin) {
96 Increase = Win - OldWin;
97 }
98
99 //
100 // Receiver's SWS: don't advertise a bigger window
101 // unless it can be increased by at least one Mss or
102 // half of the receive buffer.
103 //
104 if ((Increase > Tcb->SndMss) ||
105 (2 * Increase >= GET_RCV_BUFFSIZE (Sk))) {
106
107 return Win;
108 }
109
110 return OldWin;
111 }
112
113
114 /**
115 Compute the value to fill in the window size field
116 of the outgoing segment.
117
118 @param Tcb Pointer to the TCP_CB of this TCP instance.
119 @param Syn The flag to indicate whether the outgoing segment is a SYN
120 segment.
121
122 @return The value of the local receive window size used to fill the outing segment.
123
124 **/
125 STATIC
126 UINT16
127 TcpComputeWnd (
128 IN TCP_CB *Tcb,
129 IN BOOLEAN Syn
130 )
131 {
132 UINT32 Wnd;
133
134 //
135 // RFC requires that initial window not be scaled
136 //
137 if (Syn) {
138
139 Wnd = GET_RCV_BUFFSIZE (Tcb->Sk);
140 } else {
141
142 Wnd = TcpRcvWinNow (Tcb);
143
144 Tcb->RcvWnd = Wnd;
145 }
146
147 Wnd = NET_MIN (Wnd >> Tcb->RcvWndScale, 0xffff);
148 return NTOHS ((UINT16) Wnd);
149 }
150
151
152 /**
153 Get the maximum SndNxt.
154
155 @param Tcb Pointer to the TCP_CB of this TCP instance.
156
157 @return The sequence number of the maximum SndNxt.
158
159 **/
160 TCP_SEQNO
161 TcpGetMaxSndNxt (
162 IN TCP_CB *Tcb
163 )
164 {
165 NET_LIST_ENTRY *Entry;
166 NET_BUF *Nbuf;
167
168 if (NetListIsEmpty (&Tcb->SndQue)) {
169 return Tcb->SndNxt;
170 }
171
172 Entry = Tcb->SndQue.BackLink;
173 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
174
175 ASSERT (TCP_SEQ_GEQ (TCPSEG_NETBUF (Nbuf)->End, Tcb->SndNxt));
176 return TCPSEG_NETBUF (Nbuf)->End;
177 }
178
179
180 /**
181 Compute how much data to send.
182
183 @param Tcb Pointer to the TCP_CB of this TCP instance.
184 @param Force Whether to ignore the sender's SWS avoidance algorithm and send
185 out data by force.
186
187 @return The length of the data can be sent, if 0, no data can be sent.
188
189 **/
190 UINT32
191 TcpDataToSend (
192 IN TCP_CB *Tcb,
193 IN INTN Force
194 )
195 {
196 SOCKET *Sk;
197 UINT32 Win;
198 UINT32 Len;
199 UINT32 Left;
200 UINT32 Limit;
201
202 Sk = Tcb->Sk;
203 ASSERT (Sk);
204
205 //
206 // TCP should NOT send data beyond the send window
207 // and congestion window. The right edge of send
208 // window is defined as SND.WL2 + SND.WND. The right
209 // edge of congestion window is defined as SND.UNA +
210 // CWND.
211 //
212 Win = 0;
213 Limit = Tcb->SndWl2 + Tcb->SndWnd;
214
215 if (TCP_SEQ_GT (Limit, Tcb->SndUna + Tcb->CWnd)) {
216
217 Limit = Tcb->SndUna + Tcb->CWnd;
218 }
219
220 if (TCP_SEQ_GT (Limit, Tcb->SndNxt)) {
221 Win = TCP_SUB_SEQ (Limit, Tcb->SndNxt);
222 }
223
224 //
225 // The data to send contains two parts: the data on the
226 // socket send queue, and the data on the TCB's send
227 // buffer. The later can be non-zero if the peer shrinks
228 // its advertised window.
229 //
230 Left = GET_SND_DATASIZE (Sk) +
231 TCP_SUB_SEQ (TcpGetMaxSndNxt (Tcb), Tcb->SndNxt);
232
233 Len = NET_MIN (Win, Left);
234
235 if (Len > Tcb->SndMss) {
236 Len = Tcb->SndMss;
237 }
238
239 if (Force || (Len == 0 && Left == 0)) {
240 return Len;
241 }
242
243 if (Len == 0 && Left != 0) {
244 goto SetPersistTimer;
245 }
246
247 //
248 // Sender's SWS avoidance: Don't send a small segment unless
249 // a)A full-sized segment can be sent,
250 // b)at least one-half of the maximum sized windows that
251 // the other end has ever advertised.
252 // c)It can send everything it has and either it isn't
253 // expecting an ACK or the Nagle algorithm is disabled.
254 //
255 if ((Len == Tcb->SndMss) || (2 * Len >= Tcb->SndWndMax)) {
256
257 return Len;
258 }
259
260 if ((Len == Left) &&
261 ((Tcb->SndNxt == Tcb->SndUna) ||
262 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_NAGLE))) {
263
264 return Len;
265 }
266
267 //
268 // RFC1122 suggests to set a timer when SWSA forbids TCP
269 // sending more data, and combine it with probe timer.
270 //
271 SetPersistTimer:
272 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {
273
274 TCP4_DEBUG_WARN (
275 ("TcpDataToSend: enter persistent state for TCB %x\n",
276 Tcb)
277 );
278
279 TcpSetProbeTimer (Tcb);
280 }
281
282 return 0;
283 }
284
285
286 /**
287 Build the TCP header of the TCP segment and transmit the
288 segment by IP.
289
290 @param Tcb Pointer to the TCP_CB of this TCP instance.
291 @param Nbuf Pointer to the buffer containing the segment to be sent out.
292
293 @retval 0 The segment is sent out successfully.
294 @retval other Error condition occurred.
295
296 **/
297 STATIC
298 INTN
299 TcpTransmitSegment (
300 IN TCP_CB *Tcb,
301 IN NET_BUF *Nbuf
302 )
303 {
304 UINT16 Len;
305 TCP_HEAD *Head;
306 TCP_SEG *Seg;
307 BOOLEAN Syn;
308 UINT32 DataLen;
309
310 ASSERT (Nbuf && (Nbuf->Tcp == NULL) && TcpVerifySegment (Nbuf));
311
312 DataLen = Nbuf->TotalSize;
313
314 Seg = TCPSEG_NETBUF (Nbuf);
315 Syn = TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN);
316
317 if (Syn) {
318
319 Len = TcpSynBuildOption (Tcb, Nbuf);
320 } else {
321
322 Len = TcpBuildOption (Tcb, Nbuf);
323 }
324
325 ASSERT ((Len % 4 == 0) && (Len <= 40));
326
327 Len += sizeof (TCP_HEAD);
328
329 Head = (TCP_HEAD *) NetbufAllocSpace (
330 Nbuf,
331 sizeof (TCP_HEAD),
332 NET_BUF_HEAD
333 );
334
335 ASSERT (Head != NULL);
336
337 Nbuf->Tcp = Head;
338
339 Head->SrcPort = Tcb->LocalEnd.Port;
340 Head->DstPort = Tcb->RemoteEnd.Port;
341 Head->Seq = NTOHL (Seg->Seq);
342 Head->Ack = NTOHL (Tcb->RcvNxt);
343 Head->HeadLen = (UINT8) (Len >> 2);
344 Head->Res = 0;
345 Head->Wnd = TcpComputeWnd (Tcb, Syn);
346 Head->Checksum = 0;
347
348 //
349 // Check whether to set the PSH flag.
350 //
351 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_PSH);
352
353 if (DataLen != 0) {
354 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_PSH) &&
355 TCP_SEQ_BETWEEN (Seg->Seq, Tcb->SndPsh, Seg->End)) {
356
357 TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);
358 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_SND_PSH);
359
360 } else if ((Seg->End == Tcb->SndNxt) &&
361 (GET_SND_DATASIZE (Tcb->Sk) == 0)) {
362
363 TCP_SET_FLG (Seg->Flag, TCP_FLG_PSH);
364 }
365 }
366
367 //
368 // Check whether to set the URG flag and the urgent pointer.
369 //
370 TCP_CLEAR_FLG (Seg->Flag, TCP_FLG_URG);
371
372 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_URG) &&
373 TCP_SEQ_LEQ (Seg->Seq, Tcb->SndUp)) {
374
375 TCP_SET_FLG (Seg->Flag, TCP_FLG_URG);
376
377 if (TCP_SEQ_LT (Tcb->SndUp, Seg->End)) {
378
379 Seg->Urg = (UINT16) TCP_SUB_SEQ (Tcb->SndUp, Seg->Seq);
380 } else {
381
382 Seg->Urg = (UINT16) NET_MIN (
383 TCP_SUB_SEQ (Tcb->SndUp,
384 Seg->Seq),
385 0xffff
386 );
387 }
388 }
389
390 Head->Flag = Seg->Flag;
391 Head->Urg = NTOHS (Seg->Urg);
392 Head->Checksum = TcpChecksum (Nbuf, Tcb->HeadSum);
393
394 //
395 // update the TCP session's control information
396 //
397 Tcb->RcvWl2 = Tcb->RcvNxt;
398 if (Syn) {
399 Tcb->RcvWnd = NTOHS (Head->Wnd);
400 }
401
402 //
403 // clear delayedack flag
404 //
405 Tcb->DelayedAck = 0;
406
407 return TcpSendIpPacket (Tcb, Nbuf, Tcb->LocalEnd.Ip, Tcb->RemoteEnd.Ip);
408 }
409
410
411 /**
412 Get a segment from the Tcb's SndQue.
413
414 @param Tcb Pointer to the TCP_CB of this TCP instance.
415 @param Seq The sequence number of the segment.
416 @param Len The maximum length of the segment.
417
418 @return Pointer to the segment, if NULL some error occurred.
419
420 **/
421 NET_BUF *
422 TcpGetSegmentSndQue (
423 IN TCP_CB *Tcb,
424 IN TCP_SEQNO Seq,
425 IN UINT32 Len
426 )
427 {
428 NET_LIST_ENTRY *Head;
429 NET_LIST_ENTRY *Cur;
430 NET_BUF *Node;
431 TCP_SEG *Seg;
432 NET_BUF *Nbuf;
433 TCP_SEQNO End;
434 UINT8 *Data;
435 UINT8 Flag;
436 INT32 Offset;
437 INT32 CopyLen;
438
439 ASSERT (Tcb && TCP_SEQ_LEQ (Seq, Tcb->SndNxt) && (Len > 0));
440
441 //
442 // Find the segment that contains the Seq.
443 //
444 Head = &Tcb->SndQue;
445
446 Node = NULL;
447 Seg = NULL;
448
449 NET_LIST_FOR_EACH (Cur, Head) {
450 Node = NET_LIST_USER_STRUCT (Cur, NET_BUF, List);
451 Seg = TCPSEG_NETBUF (Node);
452
453 if (TCP_SEQ_LT (Seq, Seg->End) && TCP_SEQ_LEQ (Seg->Seq, Seq)) {
454
455 break;
456 }
457 }
458
459 ASSERT (Cur != Head);
460
461 //
462 // Return the buffer if it can be returned without
463 // adjustment:
464 //
465 if ((Seg->Seq == Seq) &&
466 TCP_SEQ_LEQ (Seg->End, Seg->Seq + Len) &&
467 !NET_BUF_SHARED (Node)) {
468
469 NET_GET_REF (Node);
470 return Node;
471 }
472
473 //
474 // Create a new buffer and copy data there.
475 //
476 Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);
477
478 if (Nbuf == NULL) {
479 return NULL;
480 }
481
482 NetbufReserve (Nbuf, TCP_MAX_HEAD);
483
484 Flag = Seg->Flag;
485 End = Seg->End;
486
487 if (TCP_SEQ_LT (Seq + Len, Seg->End)) {
488 End = Seq + Len;
489 }
490
491 CopyLen = TCP_SUB_SEQ (End, Seq);
492 Offset = TCP_SUB_SEQ (Seq, Seg->Seq);
493
494 //
495 // If SYN is set and out of the range, clear the flag.
496 // Becuase the sequence of the first byte is SEG.SEQ+1,
497 // adjust Offset by -1. If SYN is in the range, copy
498 // one byte less.
499 //
500 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
501
502 if (TCP_SEQ_LT (Seg->Seq, Seq)) {
503
504 TCP_CLEAR_FLG (Flag, TCP_FLG_SYN);
505 Offset--;
506 } else {
507
508 CopyLen--;
509 }
510 }
511
512 //
513 // If FIN is set and in the range, copy one byte less,
514 // and if it is out of the range, clear the flag.
515 //
516 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
517
518 if (Seg->End == End) {
519
520 CopyLen--;
521 } else {
522
523 TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);
524 }
525 }
526
527 ASSERT (CopyLen >= 0);
528
529 //
530 // copy data to the segment
531 //
532 if (CopyLen) {
533 Data = NetbufAllocSpace (Nbuf, CopyLen, NET_BUF_TAIL);
534 ASSERT (Data);
535
536 if ((INT32) NetbufCopy (Node, Offset, CopyLen, Data) != CopyLen) {
537 goto OnError;
538 }
539 }
540
541 NetCopyMem (TCPSEG_NETBUF (Nbuf), Seg, sizeof (TCP_SEG));
542
543 TCPSEG_NETBUF (Nbuf)->Seq = Seq;
544 TCPSEG_NETBUF (Nbuf)->End = End;
545 TCPSEG_NETBUF (Nbuf)->Flag = Flag;
546
547 return Nbuf;
548
549 OnError:
550 NetbufFree (Nbuf);
551 return NULL;
552 }
553
554
555 /**
556 Get a segment from the Tcb's socket buffer.
557
558 @param Tcb Pointer to the TCP_CB of this TCP instance.
559 @param Seq The sequence number of the segment.
560 @param Len The maximum length of the segment.
561
562 @return Pointer to the segment, if NULL some error occurred.
563
564 **/
565 NET_BUF *
566 TcpGetSegmentSock (
567 IN TCP_CB *Tcb,
568 IN TCP_SEQNO Seq,
569 IN UINT32 Len
570 )
571 {
572 NET_BUF *Nbuf;
573 UINT8 *Data;
574 UINT32 DataGet;
575
576 ASSERT (Tcb && Tcb->Sk);
577
578 Nbuf = NetbufAlloc (Len + TCP_MAX_HEAD);
579
580 if (Nbuf == NULL) {
581 TCP4_DEBUG_ERROR (("TcpGetSegmentSock: failed to allocate "
582 "a netbuf for TCB %x\n",Tcb));
583
584 return NULL;
585 }
586
587 NetbufReserve (Nbuf, TCP_MAX_HEAD);
588
589 DataGet = 0;
590
591 if (Len) {
592 //
593 // copy data to the segment.
594 //
595 Data = NetbufAllocSpace (Nbuf, Len, NET_BUF_TAIL);
596 ASSERT (Data);
597
598 DataGet = SockGetDataToSend (Tcb->Sk, 0, Len, Data);
599 }
600
601 NET_GET_REF (Nbuf);
602
603 TCPSEG_NETBUF (Nbuf)->Seq = Seq;
604 TCPSEG_NETBUF (Nbuf)->End = Seq + Len;
605
606 NetListInsertTail (&(Tcb->SndQue), &(Nbuf->List));
607
608 if (DataGet != 0) {
609
610 SockDataSent (Tcb->Sk, DataGet);
611 }
612
613 return Nbuf;
614 }
615
616
617 /**
618 Get a segment starting from sequence Seq of a maximum
619 length of Len.
620
621 @param Tcb Pointer to the TCP_CB of this TCP instance.
622 @param Seq The sequence number of the segment.
623 @param Len The maximum length of the segment.
624
625 @return Pointer to the segment, if NULL some error occurred.
626
627 **/
628 NET_BUF *
629 TcpGetSegment (
630 IN TCP_CB *Tcb,
631 IN TCP_SEQNO Seq,
632 IN UINT32 Len
633 )
634 {
635 NET_BUF *Nbuf;
636
637 ASSERT (Tcb);
638
639 //
640 // Compare the SndNxt with the max sequence number sent.
641 //
642 if ((Len != 0) && TCP_SEQ_LT (Seq, TcpGetMaxSndNxt (Tcb))) {
643
644 Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);
645 } else {
646
647 Nbuf = TcpGetSegmentSock (Tcb, Seq, Len);
648 }
649
650 ASSERT (TcpVerifySegment (Nbuf));
651 return Nbuf;
652 }
653
654
655 /**
656 Retransmit the segment from sequence Seq.
657
658 @param Tcb Pointer to the TCP_CB of this TCP instance.
659 @param Seq The sequence number of the segment to be retransmitted.
660
661 @retval 0 Retransmission succeeded.
662 @retval -1 Error condition occurred.
663
664 **/
665 INTN
666 TcpRetransmit (
667 IN TCP_CB *Tcb,
668 IN TCP_SEQNO Seq
669 )
670 {
671 NET_BUF *Nbuf;
672 UINT32 Len;
673
674 //
675 // Compute the maxium length of retransmission. It is
676 // limited by three factors:
677 // 1. Less than SndMss
678 // 2. must in the current send window
679 // 3. will not change the boundaries of queued segments.
680 //
681 if (TCP_SEQ_LT (Tcb->SndWl2 + Tcb->SndWnd, Seq)) {
682 TCP4_DEBUG_WARN (("TcpRetransmit: retransmission cancelled "
683 "because send window too small for TCB %x\n", Tcb));
684
685 return 0;
686 }
687
688 Len = TCP_SUB_SEQ (Tcb->SndWl2 + Tcb->SndWnd, Seq);
689 Len = NET_MIN (Len, Tcb->SndMss);
690
691 Nbuf = TcpGetSegmentSndQue (Tcb, Seq, Len);
692 if (Nbuf == NULL) {
693 return -1;
694 }
695
696 ASSERT (TcpVerifySegment (Nbuf));
697
698 if (TcpTransmitSegment (Tcb, Nbuf) != 0) {
699 goto OnError;
700 }
701
702 //
703 // The retransmitted buffer may be on the SndQue,
704 // trim TCP head because all the buffer on SndQue
705 // are headless.
706 //
707 ASSERT (Nbuf->Tcp);
708 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
709 Nbuf->Tcp = NULL;
710
711 NetbufFree (Nbuf);
712 return 0;
713
714 OnError:
715 if (Nbuf != NULL) {
716 NetbufFree (Nbuf);
717 }
718
719 return -1;
720 }
721
722
723 /**
724 Check whether to send data/SYN/FIN and piggy back an ACK.
725
726 @param Tcb Pointer to the TCP_CB of this TCP instance.
727 @param Force Whether to ignore the sender's SWS avoidance algorithm and send
728 out data by force.
729
730 @return The number of bytes sent.
731
732 **/
733 INTN
734 TcpToSendData (
735 IN TCP_CB *Tcb,
736 IN INTN Force
737 )
738 {
739 UINT32 Len;
740 INTN Sent;
741 UINT8 Flag;
742 NET_BUF *Nbuf;
743 TCP_SEG *Seg;
744 TCP_SEQNO Seq;
745 TCP_SEQNO End;
746
747 ASSERT (Tcb && Tcb->Sk && (Tcb->State != TCP_LISTEN));
748
749 Sent = 0;
750
751 if ((Tcb->State == TCP_CLOSED) ||
752 TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT)) {
753
754 return 0;
755 }
756
757 SEND_AGAIN:
758 //
759 // compute how much data can be sent
760 //
761 Len = TcpDataToSend (Tcb, Force);
762 Seq = Tcb->SndNxt;
763
764 Flag = mTcpOutFlag[Tcb->State];
765
766 if (Flag & TCP_FLG_SYN) {
767
768 Seq = Tcb->Iss;
769 Len = 0;
770 }
771
772 //
773 // only send a segment without data if SYN or
774 // FIN is set.
775 //
776 if ((Len == 0) && !(Flag & (TCP_FLG_SYN | TCP_FLG_FIN))) {
777 return Sent;
778 }
779
780 Nbuf = TcpGetSegment (Tcb, Seq, Len);
781
782 if (Nbuf == NULL) {
783 TCP4_DEBUG_ERROR (
784 ("TcpToSendData: failed to get a segment for TCB %x\n",
785 Tcb)
786 );
787
788 goto OnError;
789 }
790
791 Seg = TCPSEG_NETBUF (Nbuf);
792
793 //
794 // Set the TcpSeg in Nbuf.
795 //
796 Len = Nbuf->TotalSize;
797 End = Seq + Len;
798 if (TCP_FLG_ON (Flag, TCP_FLG_SYN)) {
799 End++;
800 }
801
802 if (Flag & TCP_FLG_FIN) {
803 //
804 // Send FIN if all data is sent, and FIN is
805 // in the window
806 //
807 if ((TcpGetMaxSndNxt (Tcb) == Tcb->SndNxt) &&
808 (GET_SND_DATASIZE (Tcb->Sk) == 0) &&
809 TCP_SEQ_LT (End + 1, Tcb->SndWnd + Tcb->SndWl2)
810 ) {
811
812 TCP4_DEBUG_TRACE (("TcpToSendData: send FIN "
813 "to peer for TCB %x in state %d\n", Tcb, Tcb->State));
814
815 End++;
816 } else {
817 TCP_CLEAR_FLG (Flag, TCP_FLG_FIN);
818 }
819 }
820
821 Seg->Seq = Seq;
822 Seg->End = End;
823 Seg->Flag = Flag;
824
825 ASSERT (TcpVerifySegment (Nbuf));
826 ASSERT (TcpCheckSndQue (&Tcb->SndQue));
827
828 //
829 // don't send an empty segment here.
830 //
831 if (Seg->End == Seg->Seq) {
832 TCP4_DEBUG_WARN (("TcpToSendData: created a empty"
833 " segment for TCB %x, free it now\n", Tcb));
834
835 NetbufFree (Nbuf);
836 return Sent;
837 }
838
839 if (TcpTransmitSegment (Tcb, Nbuf) != 0) {
840 //
841 // TODO: double check this
842 //
843 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
844 Nbuf->Tcp = NULL;
845
846 if (Flag & TCP_FLG_FIN) {
847 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);
848 }
849
850 goto OnError;
851 }
852
853 Sent += TCP_SUB_SEQ (End, Seq);
854
855 //
856 // All the buffer in the SndQue is headless
857 //
858 ASSERT (Nbuf->Tcp);
859
860 NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
861 Nbuf->Tcp = NULL;
862
863 NetbufFree (Nbuf);
864
865 //
866 // update status in TCB
867 //
868 Tcb->DelayedAck = 0;
869
870 if (Flag & TCP_FLG_FIN) {
871 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);
872 }
873
874 if (TCP_SEQ_GT (End, Tcb->SndNxt)) {
875 Tcb->SndNxt = End;
876 }
877
878 if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {
879 TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
880 }
881
882 //
883 // Enable RTT measurement only if not in retransmit.
884 // Karn's algorithm reqires not to update RTT when in loss.
885 //
886 if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&
887 !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
888
889 TCP4_DEBUG_TRACE (("TcpToSendData: set RTT measure "
890 "sequence %d for TCB %x\n", Seq, Tcb));
891
892 TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
893 Tcb->RttSeq = Seq;
894 Tcb->RttMeasure = 0;
895 }
896
897 if (Len == Tcb->SndMss) {
898 goto SEND_AGAIN;
899 }
900
901 return Sent;
902
903 OnError:
904 if (Nbuf != NULL) {
905 NetbufFree (Nbuf);
906 }
907
908 return Sent;
909 }
910
911
912 /**
913 Send an ACK immediately.
914
915 @param Tcb Pointer to the TCP_CB of this TCP instance.
916
917 @return None.
918
919 **/
920 VOID
921 TcpSendAck (
922 IN TCP_CB *Tcb
923 )
924 {
925 NET_BUF *Nbuf;
926 TCP_SEG *Seg;
927
928 Nbuf = NetbufAlloc (TCP_MAX_HEAD);
929
930 if (Nbuf == NULL) {
931 return;
932 }
933
934 NetbufReserve (Nbuf, TCP_MAX_HEAD);
935
936 Seg = TCPSEG_NETBUF (Nbuf);
937 Seg->Seq = Tcb->SndNxt;
938 Seg->End = Tcb->SndNxt;
939 Seg->Flag = TCP_FLG_ACK;
940
941 if (TcpTransmitSegment (Tcb, Nbuf) == 0) {
942 TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
943 Tcb->DelayedAck = 0;
944 }
945
946 NetbufFree (Nbuf);
947 }
948
949
950 /**
951 Send a zero probe segment. It can be used by keepalive
952 and zero window probe.
953
954 @param Tcb Pointer to the TCP_CB of this TCP instance.
955
956 @retval 0 The zero probe segment was sent out successfully.
957 @retval other Error condition occurred.
958
959 **/
960 INTN
961 TcpSendZeroProbe (
962 IN TCP_CB *Tcb
963 )
964 {
965 NET_BUF *Nbuf;
966 TCP_SEG *Seg;
967 INTN Result;
968
969 Nbuf = NetbufAlloc (TCP_MAX_HEAD);
970
971 if (Nbuf == NULL) {
972 return -1;
973 }
974
975 NetbufReserve (Nbuf, TCP_MAX_HEAD);
976
977 //
978 // SndNxt-1 is out of window. The peer should respond
979 // with an ACK.
980 //
981 Seg = TCPSEG_NETBUF (Nbuf);
982 Seg->Seq = Tcb->SndNxt - 1;
983 Seg->End = Tcb->SndNxt - 1;
984 Seg->Flag = TCP_FLG_ACK;
985
986 Result = TcpTransmitSegment (Tcb, Nbuf);
987 NetbufFree (Nbuf);
988
989 return Result;
990 }
991
992
993 /**
994 Check whether to send an ACK or delayed ACK.
995
996 @param Tcb Pointer to the TCP_CB of this TCP instance.
997
998 @return None.
999
1000 **/
1001 VOID
1002 TcpToSendAck (
1003 IN TCP_CB *Tcb
1004 )
1005 {
1006 UINT32 TcpNow;
1007
1008 TcpNow = TcpRcvWinNow (Tcb);
1009 //
1010 // Generally, TCP should send a delayed ACK unless:
1011 // 1. ACK at least every other FULL sized segment received,
1012 // 2. Packets received out of order
1013 // 3. Receiving window is open
1014 //
1015 if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) ||
1016 (Tcb->DelayedAck >= 1) ||
1017 (TcpNow > TcpRcvWinOld (Tcb))
1018 ) {
1019 TcpSendAck (Tcb);
1020 return;
1021 }
1022
1023 TCP4_DEBUG_TRACE (("TcpToSendAck: scheduled a delayed"
1024 " ACK for TCB %x\n", Tcb));
1025
1026 //
1027 // schedule a delayed ACK
1028 //
1029 Tcb->DelayedAck++;
1030 }
1031
1032
1033 /**
1034 Send a RESET segment in response to the segment received.
1035
1036 @param Tcb Pointer to the TCP_CB of this TCP instance, may be NULL.
1037 @param Head TCP header of the segment that triggers the reset.
1038 @param Len Length of the segment that triggers the reset.
1039 @param Local Local IP address.
1040 @param Remote Remote peer's IP address.
1041
1042 @retval 0 A reset is sent or no need to send it.
1043 @retval -1 No reset is sent.
1044
1045 **/
1046 INTN
1047 TcpSendReset (
1048 IN TCP_CB *Tcb,
1049 IN TCP_HEAD *Head,
1050 IN INT32 Len,
1051 IN UINT32 Local,
1052 IN UINT32 Remote
1053 )
1054 {
1055 NET_BUF *Nbuf;
1056 TCP_HEAD *Nhead;
1057 UINT16 HeadSum;
1058
1059 //
1060 // Don't respond to a Reset with reset
1061 //
1062 if (Head->Flag & TCP_FLG_RST) {
1063 return 0;
1064 }
1065
1066 Nbuf = NetbufAlloc (TCP_MAX_HEAD);
1067
1068 if (Nbuf == NULL) {
1069 return -1;
1070 }
1071
1072 Nhead = (TCP_HEAD *) NetbufAllocSpace (
1073 Nbuf,
1074 sizeof (TCP_HEAD),
1075 NET_BUF_TAIL
1076 );
1077
1078 ASSERT (Nhead != NULL);
1079
1080 Nbuf->Tcp = Nhead;
1081 Nhead->Flag = TCP_FLG_RST;
1082
1083 //
1084 // Derive Seq/ACK from the segment if no TCB
1085 // associated with it, otherwise from the Tcb
1086 //
1087 if (Tcb == NULL) {
1088
1089 if (TCP_FLG_ON (Head->Flag, TCP_FLG_ACK)) {
1090 Nhead->Seq = Head->Ack;
1091 Nhead->Ack = 0;
1092 } else {
1093 Nhead->Seq = 0;
1094 TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);
1095 Nhead->Ack = HTONL (NTOHL (Head->Seq) + Len);
1096 }
1097 } else {
1098
1099 Nhead->Seq = HTONL (Tcb->SndNxt);
1100 Nhead->Ack = HTONL (Tcb->RcvNxt);
1101 TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);
1102 }
1103
1104 Nhead->SrcPort = Head->DstPort;
1105 Nhead->DstPort = Head->SrcPort;
1106 Nhead->HeadLen = (sizeof (TCP_HEAD) >> 2);
1107 Nhead->Res = 0;
1108 Nhead->Wnd = HTONS (0xFFFF);
1109 Nhead->Checksum = 0;
1110 Nhead->Urg = 0;
1111
1112 HeadSum = NetPseudoHeadChecksum (Local, Remote, 6, 0);
1113 Nhead->Checksum = TcpChecksum (Nbuf, HeadSum);
1114
1115 TcpSendIpPacket (Tcb, Nbuf, Local, Remote);
1116
1117 NetbufFree (Nbuf);
1118 return 0;
1119 }
1120
1121
1122 /**
1123 Verify that the segment is in good shape.
1124
1125 @param Nbuf Buffer that contains the segment to be checked.
1126
1127 @retval 0 The segment is broken.
1128 @retval 1 The segment is in good shape.
1129
1130 **/
1131 INTN
1132 TcpVerifySegment (
1133 IN NET_BUF *Nbuf
1134 )
1135 {
1136 TCP_HEAD *Head;
1137 TCP_SEG *Seg;
1138 UINT32 Len;
1139
1140 if (Nbuf == NULL) {
1141 return 1;
1142 }
1143
1144 NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1145
1146 Seg = TCPSEG_NETBUF (Nbuf);
1147 Len = Nbuf->TotalSize;
1148 Head = Nbuf->Tcp;
1149
1150 if (Head != NULL) {
1151 if (Head->Flag != Seg->Flag) {
1152 return 0;
1153 }
1154
1155 Len -= (Head->HeadLen << 2);
1156 }
1157
1158 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
1159 Len++;
1160 }
1161
1162 if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
1163 Len++;
1164 }
1165
1166 if (Seg->Seq + Len != Seg->End) {
1167 return 0;
1168 }
1169
1170 return 1;
1171 }
1172
1173
1174 /**
1175 Verify that all the segments in SndQue are in good shape.
1176
1177 @param Head Pointer to the head node of the SndQue.
1178
1179 @retval 0 At least one segment is broken.
1180 @retval 1 All segments in the specific queue are in good shape.
1181
1182 **/
1183 INTN
1184 TcpCheckSndQue (
1185 IN NET_LIST_ENTRY *Head
1186 )
1187 {
1188 NET_LIST_ENTRY *Entry;
1189 NET_BUF *Nbuf;
1190 TCP_SEQNO Seq;
1191
1192 if (NetListIsEmpty (Head)) {
1193 return 1;
1194 }
1195 //
1196 // Initialize the Seq
1197 //
1198 Entry = Head->ForwardLink;
1199 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1200 Seq = TCPSEG_NETBUF (Nbuf)->Seq;
1201
1202 NET_LIST_FOR_EACH (Entry, Head) {
1203 Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1204
1205 if (TcpVerifySegment (Nbuf) == 0) {
1206 return 0;
1207 }
1208
1209 //
1210 // All the node in the SndQue should has:
1211 // SEG.SEQ = LAST_SEG.END
1212 //
1213 if (Seq != TCPSEG_NETBUF (Nbuf)->Seq) {
1214 return 0;
1215 }
1216
1217 Seq = TCPSEG_NETBUF (Nbuf)->End;
1218 }
1219
1220 return 1;
1221 }