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