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