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