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