1 /** @file
2   TCP output process routines.
3 
4 Copyright (c) 2005 - 2016, 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
TcpRcvWinOld(IN TCP_CB * Tcb)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
TcpRcvWinNow(IN TCP_CB * Tcb)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
TcpComputeWnd(IN OUT TCP_CB * Tcb,IN BOOLEAN Syn)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
TcpGetMaxSndNxt(IN TCP_CB * Tcb)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
TcpDataToSend(IN TCP_CB * Tcb,IN INTN Force)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
TcpTransmitSegment(IN OUT TCP_CB * Tcb,IN NET_BUF * Nbuf)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 *
TcpGetSegmentSndQue(IN TCP_CB * Tcb,IN TCP_SEQNO Seq,IN UINT32 Len)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 *
TcpGetSegmentSock(IN TCP_CB * Tcb,IN TCP_SEQNO Seq,IN UINT32 Len)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 *
TcpGetSegment(IN TCP_CB * Tcb,IN TCP_SEQNO Seq,IN UINT32 Len)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
TcpRetransmit(IN TCP_CB * Tcb,IN TCP_SEQNO Seq)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   if (TCP_SEQ_LT (Tcb->SndWl2 + Tcb->SndWnd, Seq)) {
675     DEBUG ((EFI_D_WARN, "TcpRetransmit: retransmission cancelled "
676       "because send window too small for TCB %p\n", Tcb));
677 
678     return 0;
679   }
680 
681   Len   = TCP_SUB_SEQ (Tcb->SndWl2 + Tcb->SndWnd, Seq);
682   Len   = MIN (Len, Tcb->SndMss);
683 
684   Nbuf  = TcpGetSegmentSndQue (Tcb, Seq, Len);
685   if (Nbuf == NULL) {
686     return -1;
687   }
688 
689   ASSERT (TcpVerifySegment (Nbuf) != 0);
690 
691   if (TcpTransmitSegment (Tcb, Nbuf) != 0) {
692     goto OnError;
693   }
694 
695   //
696   // The retransmitted buffer may be on the SndQue,
697   // trim TCP head because all the buffer on SndQue
698   // are headless.
699   //
700   ASSERT (Nbuf->Tcp != NULL);
701   NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
702   Nbuf->Tcp = NULL;
703 
704   NetbufFree (Nbuf);
705   return 0;
706 
707 OnError:
708   if (Nbuf != NULL) {
709     NetbufFree (Nbuf);
710   }
711 
712   return -1;
713 }
714 
715 
716 /**
717   Check whether to send data/SYN/FIN and piggy back an ACK.
718 
719   @param  Tcb     Pointer to the TCP_CB of this TCP instance.
720   @param  Force   Whether to ignore the sender's SWS avoidance algorithm and send
721                   out data by force.
722 
723   @return The number of bytes sent.
724 
725 **/
726 INTN
TcpToSendData(IN OUT TCP_CB * Tcb,IN INTN Force)727 TcpToSendData (
728   IN OUT TCP_CB *Tcb,
729   IN     INTN Force
730   )
731 {
732   UINT32    Len;
733   INTN      Sent;
734   UINT8     Flag;
735   NET_BUF   *Nbuf;
736   TCP_SEG   *Seg;
737   TCP_SEQNO Seq;
738   TCP_SEQNO End;
739 
740   ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL) && (Tcb->State != TCP_LISTEN));
741 
742   Sent = 0;
743 
744   if ((Tcb->State == TCP_CLOSED) ||
745       TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT)) {
746 
747     return 0;
748   }
749 
750 SEND_AGAIN:
751   //
752   // compute how much data can be sent
753   //
754   Len   = TcpDataToSend (Tcb, Force);
755   Seq   = Tcb->SndNxt;
756 
757   ASSERT ((Tcb->State) < (ARRAY_SIZE (mTcpOutFlag)));
758   Flag  = mTcpOutFlag[Tcb->State];
759 
760   if ((Flag & TCP_FLG_SYN) != 0) {
761 
762     Seq = Tcb->Iss;
763     Len = 0;
764   }
765 
766   //
767   // only send a segment without data if SYN or
768   // FIN is set.
769   //
770   if ((Len == 0) &&
771       ((Flag & (TCP_FLG_SYN | TCP_FLG_FIN)) == 0)) {
772     return Sent;
773   }
774 
775   Nbuf = TcpGetSegment (Tcb, Seq, Len);
776 
777   if (Nbuf == NULL) {
778     DEBUG (
779       (EFI_D_ERROR,
780       "TcpToSendData: failed to get a segment for TCB %p\n",
781       Tcb)
782       );
783 
784     goto OnError;
785   }
786 
787   Seg = TCPSEG_NETBUF (Nbuf);
788 
789   //
790   // Set the TcpSeg in Nbuf.
791   //
792   Len = Nbuf->TotalSize;
793   End = Seq + Len;
794   if (TCP_FLG_ON (Flag, TCP_FLG_SYN)) {
795     End++;
796   }
797 
798   if ((Flag & TCP_FLG_FIN) != 0) {
799     //
800     // Send FIN if all data is sent, and FIN is
801     // in the window
802     //
803     if ((TcpGetMaxSndNxt (Tcb) == Tcb->SndNxt) &&
804         (GET_SND_DATASIZE (Tcb->Sk) == 0) &&
805         TCP_SEQ_LT (End + 1, Tcb->SndWnd + Tcb->SndWl2)) {
806 
807       DEBUG (
808 	  	(EFI_D_NET,
809 	  	"TcpToSendData: send FIN "
810         "to peer for TCB %p in state %s\n",
811         Tcb,
812         mTcpStateName[Tcb->State])
813       );
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) != 0);
826   ASSERT (TcpCheckSndQue (&Tcb->SndQue) != 0);
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     NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
841     Nbuf->Tcp = NULL;
842 
843     if ((Flag & TCP_FLG_FIN) != 0)  {
844       TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);
845     }
846 
847     goto OnError;
848   }
849 
850   Sent += TCP_SUB_SEQ (End, Seq);
851 
852   //
853   // All the buffer in the SndQue is headless
854   //
855   ASSERT (Nbuf->Tcp != NULL);
856 
857   NetbufTrim (Nbuf, (Nbuf->Tcp->HeadLen << 2), NET_BUF_HEAD);
858   Nbuf->Tcp = NULL;
859 
860   NetbufFree (Nbuf);
861 
862   //
863   // update status in TCB
864   //
865   Tcb->DelayedAck = 0;
866 
867   if ((Flag & TCP_FLG_FIN) != 0) {
868     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_FIN_SENT);
869   }
870 
871   if (TCP_SEQ_GT (End, Tcb->SndNxt)) {
872     Tcb->SndNxt = End;
873   }
874 
875   if (!TCP_TIMER_ON (Tcb->EnabledTimer, TCP_TIMER_REXMIT)) {
876     TcpSetTimer (Tcb, TCP_TIMER_REXMIT, Tcb->Rto);
877   }
878 
879   //
880   // Enable RTT measurement only if not in retransmit.
881   // Karn's algorithm reqires not to update RTT when in loss.
882   //
883   if ((Tcb->CongestState == TCP_CONGEST_OPEN) &&
884       !TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RTT_ON)) {
885 
886     DEBUG ((EFI_D_NET, "TcpToSendData: set RTT measure "
887       "sequence %d for TCB %p\n", Seq, Tcb));
888 
889     TCP_SET_FLG (Tcb->CtrlFlag, TCP_CTRL_RTT_ON);
890     Tcb->RttSeq     = Seq;
891     Tcb->RttMeasure = 0;
892   }
893 
894   if (Len == Tcb->SndMss) {
895     goto SEND_AGAIN;
896   }
897 
898   return Sent;
899 
900 OnError:
901   if (Nbuf != NULL) {
902     NetbufFree (Nbuf);
903   }
904 
905   return Sent;
906 }
907 
908 
909 /**
910   Send an ACK immediately.
911 
912   @param  Tcb     Pointer to the TCP_CB of this TCP instance.
913 
914 **/
915 VOID
TcpSendAck(IN OUT TCP_CB * Tcb)916 TcpSendAck (
917   IN OUT TCP_CB *Tcb
918   )
919 {
920   NET_BUF *Nbuf;
921   TCP_SEG *Seg;
922 
923   Nbuf = NetbufAlloc (TCP_MAX_HEAD);
924 
925   if (Nbuf == NULL) {
926     return;
927   }
928 
929   NetbufReserve (Nbuf, TCP_MAX_HEAD);
930 
931   Seg       = TCPSEG_NETBUF (Nbuf);
932   Seg->Seq  = Tcb->SndNxt;
933   Seg->End  = Tcb->SndNxt;
934   Seg->Flag = TCP_FLG_ACK;
935 
936   if (TcpTransmitSegment (Tcb, Nbuf) == 0) {
937     TCP_CLEAR_FLG (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW);
938     Tcb->DelayedAck = 0;
939   }
940 
941   NetbufFree (Nbuf);
942 }
943 
944 
945 /**
946   Send a zero probe segment. It can be used by keepalive and zero window probe.
947 
948   @param  Tcb     Pointer to the TCP_CB of this TCP instance.
949 
950   @retval 0       The zero probe segment was sent out successfully.
951   @retval other   Error condition occurred.
952 
953 **/
954 INTN
TcpSendZeroProbe(IN OUT TCP_CB * Tcb)955 TcpSendZeroProbe (
956   IN OUT TCP_CB *Tcb
957   )
958 {
959   NET_BUF *Nbuf;
960   TCP_SEG *Seg;
961   INTN     Result;
962 
963   Nbuf = NetbufAlloc (TCP_MAX_HEAD);
964 
965   if (Nbuf == NULL) {
966     return -1;
967   }
968 
969   NetbufReserve (Nbuf, TCP_MAX_HEAD);
970 
971   //
972   // SndNxt-1 is out of window. The peer should respond
973   // with an ACK.
974   //
975   Seg       = TCPSEG_NETBUF (Nbuf);
976   Seg->Seq  = Tcb->SndNxt - 1;
977   Seg->End  = Tcb->SndNxt - 1;
978   Seg->Flag = TCP_FLG_ACK;
979 
980   Result    = TcpTransmitSegment (Tcb, Nbuf);
981   NetbufFree (Nbuf);
982 
983   return Result;
984 }
985 
986 
987 /**
988   Check whether to send an ACK or delayed ACK.
989 
990   @param  Tcb     Pointer to the TCP_CB of this TCP instance.
991 
992 **/
993 VOID
TcpToSendAck(IN OUT TCP_CB * Tcb)994 TcpToSendAck (
995   IN OUT TCP_CB *Tcb
996   )
997 {
998   UINT32 TcpNow;
999 
1000   TcpNow = TcpRcvWinNow (Tcb);
1001   //
1002   // Generally, TCP should send a delayed ACK unless:
1003   //   1. ACK at least every other FULL sized segment received,
1004   //   2. Packets received out of order
1005   //   3. Receiving window is open
1006   //
1007   if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_ACK_NOW) ||
1008       (Tcb->DelayedAck >= 1) ||
1009       (TcpNow > TcpRcvWinOld (Tcb))) {
1010     TcpSendAck (Tcb);
1011     return;
1012   }
1013 
1014   DEBUG ((EFI_D_NET, "TcpToSendAck: scheduled a delayed"
1015     " ACK for TCB %p\n", Tcb));
1016 
1017   //
1018   // schedule a delayed ACK
1019   //
1020   Tcb->DelayedAck++;
1021 }
1022 
1023 
1024 /**
1025   Send a RESET segment in response to the segment received.
1026 
1027   @param  Tcb     Pointer to the TCP_CB of this TCP instance, may be NULL.
1028   @param  Head    TCP header of the segment that triggers the reset.
1029   @param  Len     Length of the segment that triggers the reset.
1030   @param  Local   Local IP address.
1031   @param  Remote  Remote peer's IP address.
1032 
1033   @retval 0       A reset is sent or no need to send it.
1034   @retval -1      No reset is sent.
1035 
1036 **/
1037 INTN
TcpSendReset(IN TCP_CB * Tcb,IN TCP_HEAD * Head,IN INT32 Len,IN UINT32 Local,IN UINT32 Remote)1038 TcpSendReset (
1039   IN TCP_CB    *Tcb,
1040   IN TCP_HEAD  *Head,
1041   IN INT32     Len,
1042   IN UINT32    Local,
1043   IN UINT32    Remote
1044   )
1045 {
1046   NET_BUF   *Nbuf;
1047   TCP_HEAD  *Nhead;
1048   UINT16    HeadSum;
1049 
1050   //
1051   // Don't respond to a Reset with reset
1052   //
1053   if ((Head->Flag & TCP_FLG_RST) != 0) {
1054     return 0;
1055   }
1056 
1057   Nbuf = NetbufAlloc (TCP_MAX_HEAD);
1058 
1059   if (Nbuf == NULL) {
1060     return -1;
1061   }
1062 
1063   Nhead = (TCP_HEAD *) NetbufAllocSpace (
1064                         Nbuf,
1065                         sizeof (TCP_HEAD),
1066                         NET_BUF_TAIL
1067                         );
1068 
1069   ASSERT (Nhead != NULL);
1070 
1071   Nbuf->Tcp   = Nhead;
1072   Nhead->Flag = TCP_FLG_RST;
1073 
1074   //
1075   // Derive Seq/ACK from the segment if no TCB
1076   // associated with it, otherwise from the Tcb
1077   //
1078   if (Tcb == NULL) {
1079 
1080     if (TCP_FLG_ON (Head->Flag, TCP_FLG_ACK)) {
1081       Nhead->Seq  = Head->Ack;
1082       Nhead->Ack  = 0;
1083     } else {
1084       Nhead->Seq = 0;
1085       TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);
1086       Nhead->Ack = HTONL (NTOHL (Head->Seq) + Len);
1087     }
1088   } else {
1089 
1090     Nhead->Seq  = HTONL (Tcb->SndNxt);
1091     Nhead->Ack  = HTONL (Tcb->RcvNxt);
1092     TCP_SET_FLG (Nhead->Flag, TCP_FLG_ACK);
1093   }
1094 
1095   Nhead->SrcPort  = Head->DstPort;
1096   Nhead->DstPort  = Head->SrcPort;
1097   Nhead->HeadLen  = (UINT8) (sizeof (TCP_HEAD) >> 2);
1098   Nhead->Res      = 0;
1099   Nhead->Wnd      = HTONS (0xFFFF);
1100   Nhead->Checksum = 0;
1101   Nhead->Urg      = 0;
1102 
1103   HeadSum         = NetPseudoHeadChecksum (Local, Remote, 6, 0);
1104   Nhead->Checksum = TcpChecksum (Nbuf, HeadSum);
1105 
1106   TcpSendIpPacket (Tcb, Nbuf, Local, Remote);
1107 
1108   NetbufFree (Nbuf);
1109   return 0;
1110 }
1111 
1112 
1113 /**
1114   Verify that the segment is in good shape.
1115 
1116   @param  Nbuf    Buffer that contains the segment to be checked.
1117 
1118   @retval 0       The segment is broken.
1119   @retval 1       The segment is in good shape.
1120 
1121 **/
1122 INTN
TcpVerifySegment(IN NET_BUF * Nbuf)1123 TcpVerifySegment (
1124   IN NET_BUF *Nbuf
1125   )
1126 {
1127   TCP_HEAD  *Head;
1128   TCP_SEG   *Seg;
1129   UINT32    Len;
1130 
1131   if (Nbuf == NULL) {
1132     return 1;
1133   }
1134 
1135   NET_CHECK_SIGNATURE (Nbuf, NET_BUF_SIGNATURE);
1136 
1137   Seg   = TCPSEG_NETBUF (Nbuf);
1138   Len   = Nbuf->TotalSize;
1139   Head  = Nbuf->Tcp;
1140 
1141   if (Head != NULL) {
1142     if (Head->Flag != Seg->Flag) {
1143       return 0;
1144     }
1145 
1146     Len -= (Head->HeadLen << 2);
1147   }
1148 
1149   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_SYN)) {
1150     Len++;
1151   }
1152 
1153   if (TCP_FLG_ON (Seg->Flag, TCP_FLG_FIN)) {
1154     Len++;
1155   }
1156 
1157   if (Seg->Seq + Len != Seg->End) {
1158     return 0;
1159   }
1160 
1161   return 1;
1162 }
1163 
1164 
1165 /**
1166   Verify that all the segments in SndQue are in good shape.
1167 
1168   @param  Head    Pointer to the head node of the SndQue.
1169 
1170   @retval 0       At least one segment is broken.
1171   @retval 1       All segments in the specific queue are in good shape.
1172 
1173 **/
1174 INTN
TcpCheckSndQue(IN LIST_ENTRY * Head)1175 TcpCheckSndQue (
1176   IN LIST_ENTRY     *Head
1177   )
1178 {
1179   LIST_ENTRY      *Entry;
1180   NET_BUF         *Nbuf;
1181   TCP_SEQNO       Seq;
1182 
1183   if (IsListEmpty (Head)) {
1184     return 1;
1185   }
1186   //
1187   // Initialize the Seq
1188   //
1189   Entry = Head->ForwardLink;
1190   Nbuf  = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1191   Seq   = TCPSEG_NETBUF (Nbuf)->Seq;
1192 
1193   NET_LIST_FOR_EACH (Entry, Head) {
1194     Nbuf = NET_LIST_USER_STRUCT (Entry, NET_BUF, List);
1195 
1196     if (TcpVerifySegment (Nbuf) == 0) {
1197       return 0;
1198     }
1199 
1200     //
1201     // All the node in the SndQue should has:
1202     // SEG.SEQ = LAST_SEG.END
1203     //
1204     if (Seq != TCPSEG_NETBUF (Nbuf)->Seq) {
1205       return 0;
1206     }
1207 
1208     Seq = TCPSEG_NETBUF (Nbuf)->End;
1209   }
1210 
1211   return 1;
1212 }
1213