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