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