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