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