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